Skip to content

Writing better code: it’s imperative that you are declarative

Most C# developers are very familiar with writing imperative code (even though they may not know it by that name). In this article, I will introduce you to an alternative style of programming called declarative programming. Proper declarative code is easier to read, understand, and maintain.

As professionals, we should be striving to write better code each day. If you cannot look at code you wrote three months ago with a critical eye and notice things that could be better, then you have not improved and are not challenging yourself. I challenge you to write code that is easier to read and understand by using declarative code.

First, it is important to understand what declarative code is and how it relates to imperative code.

Imperative code describes how something is done whereas declarative code describes what is being done.

Imperative code is generally difficult to read and understand. For example:

using System;
class Example { static void Main() { Int32 sum = 0; for (Int32 i = 0; i < 100; i++) { if (i % 2 == 0) { sum += i; } } Console.WriteLine(sum); } }

It is not immediately apparent what this code does. Only through careful examination can we deduce that it prints the sum of all even numbers between 0 and 99.

This is how the same program would be implemented using a declarative style:

using System;
using System.Linq;
class Example { static void Main() { Int32 sum = Enumerable.Range(0, 99) .Where(i => i % 2 == 0) .Sum(); Console.WriteLine(sum); } }

Obviously the second example is different, but is it better? I believe it is. We have condensed the example into a single expression and the expression is significantly easier to understand. The name of each method is used to express the intention of that portion of the program. Rather than looping with a classic for loop I have used the newer Enumerable.Range method. This not only better expresses my intentions, but also gives me a starting place from which I can easily stream the numbers through a filter (the Where method) and finally aggregate them with Sum.

But I still think this code could be better. Let me do one last thing to make our code even more declarative:

using System;
using System.Linq;
class Example { static void Main() { Int32 sum = Enumerable.Range(0, 99) .Where(isEven) .Sum(); Console.WriteLine(sum); } static Boolean isEven(Int32 number) { return number % 2 == 0; } }

This change is subtle, but important. We have moved the somewhat cryptic expression that tests for evenness into its own method. Since this method has a single responsibility and is clearly named, it is ideal for inclusion in our declarative expression. It is important to understand that declarative code doesn’t necessarily mean less code. Declarative code is characterized by how expressive it is. By moving the test for evenness into its own method we may have increased the line count of the program, but we have also greatly improved the readability of the code as well.

I hope that I have shown how you can improve your code by making it more declarative. If you strive to write more declarative code you will end up with better software that is easier to read, understand, and maintain.

13 Comments

  1. Bob Mottram

    Having written quite a bit of C# code I’d say that the first example is by far the clearest and least ambiguous. Looking at the second and third examples the exotic syntax means that it’s not immediately apparent to me what this code is doing. Also adding an extra method increases the complexity of the code.

    Posted on 21-Mar-10 at 12:16 pm | Permalink
  2. Josh

    Next you’ll be doing Prolog. :-0

    Posted on 21-Mar-10 at 12:33 pm | Permalink
  3. @Bob Mottram – Readability is subjective, yes, and I definitely respect the fact that you find the first example more readable. That doesn’t change the fact that it is imperative in style and my reworking of it is more declarative. I think the simplicity of the example may have tripped you up a bit as I wasn’t advocating that declarative code be used in all examples (or even examples like this) – I was simply hoping to provide a very simple example of declarative code.

    In a future article I hope to show some real-world examples that would have been out of place in an introductory article like this one. I also hope to touch on one of declarative programming’s greatest strengths (which is also out of place in an introductory article) which is ease of parallelization. I do agree with you though that there are many things about declarative programming that make it a desirable alternative to imperative programming beyond simple readability (though I felt that readability was a good place to start the discussion).

    Posted on 22-Mar-10 at 8:09 am | Permalink
  4. The problem with the alternative syntax is of performance; without proper compiler inlining, which destroys the program’s flow via cache/branch misses – plus you now have a possibly one-use method cluttering up your namespace. The first example is the best for performance, but I agree that using the second example with its natural syntax is good for non-performance critical sections.

    • Dean
    Posted on 25-Mar-10 at 6:48 am | Permalink
  5. hobbit125

    Eww…polluting the class with a one-off method. At least, use a named local lambda. Better, don’t bother. Just inline it. Most people are familiar with even check statements, and if it’s that big of a deal, throw a comment at the end of the Where line.

    Also, this is how you check for evens: (i & 1) == 0.

    Also, do you have some superstitious reason for not liking keyword types?

    Posted on 15-Apr-10 at 10:35 pm | Permalink
  6. @Dean Camera – Yes declarative code like this has the potential to have poorer performance but I believe that it is better to write the most readable code first. If it becomes apparent (through the use of a profiler) that the code is creating a bottleneck in the application’s performance only then would I consider changing it to an imperatively-styled solution.

    Posted on 16-Apr-10 at 5:45 pm | Permalink
  7. @hobbit125 – Private methods that are singular in focus like I have used here are not only appropriate but actually desired in some cases. I did consider using a named lambda expression to check for evenness but given the introductory nature of the article I decided against it. I also don’t think a comment explaining the evenness check makes a whole lot of sense given that this article is supposed to be an introduction on declarative code. You could make a case that my isEven method is unnecessary but I could just as easily make the case that you are missing the point of the article.

    I do appreciate your alternative method for checking a number for evenness. From the way you phased your statement someone could get the impression that you consider your approach to be correct and my approach incorrect. Given the fact that i & 1 == 0 provides the same exact results as i % 2 == 0 and takes about the same amount of time to execute I thought it was important to point out that both solutions are correct and can be used interchangeably.

    Finally, I am happy to report that I am in no way a superstitious person at all! I simply prefer to use the actual names of the types as they are defined in their assemblies instead of their corresponding aliases. Given the fact that the aliases are changed by the compiler into their respective type names I like to think that I am saving the compiler that trouble and therefore compiling my code at a faster rate than others who prefer to use aliases.

    Posted on 16-Apr-10 at 6:24 pm | Permalink
  8. Er.

    lists:sum( [ X || X &lt;- lists:seq(1,100), x%2 == 0] )

    That’s completely imperative code, sir. Thanks for not confusing the effects of one particular language’s syntax with those of a style of language.

    Posted on 17-Apr-10 at 1:09 pm | Permalink
  9. Alternatively,

    int Total = 0; for (int i=0; i<100; ++i) { if (i%2==0) { Total += i; }}

    You’re really just showing off the effects of a bad formatting style.

    Posted on 17-Apr-10 at 1:10 pm | Permalink
  10. @John Haugeland – I appreciate the Erlang example, your use of list.sum and list.seq both greatly contribute to its declarative nature. I am not completely certain what you meant by these two statements:

     ”Thanks for not confusing the effects of one particular language’s syntax with those of a style of language.”
     ”You’re really just showing off the effects of a bad formatting style.”

    Would you mind explaining a bit more?

    Posted on 17-Apr-10 at 1:24 pm | Permalink
  11. Michael Chandler

    I’m surprised to see so many people disagreeing with you. I totally agree with you that the readability of the second and third examples prevail. Clearly in this case it’s a trivial example, but breaking out a lambda into a separate method is a great way of self-documenting what its purpose is.

    It’s also disappointing to see that people assume that declarative performance is going to be worse than that of the imperative counterpart. How does your imperative, state-based code stack up when you need to perform in parallel? Functional / declarative programming seems to be the way forward in addressing much of these problems. You can’t just stick an .IsParallel onto the end of your imperative code, that’s for sure.

    The comment about using & vs % is just silly. Either work fine. In my opinion modulus is a ‘higher level of abstraction’ than the bitwise operator, so I would generally using it. (Yes, even if it’s an operation slower.)

    I’ve added your blog to my Google Reader. :)

    Posted on 24-Apr-10 at 8:22 am | Permalink
  12. @Michael Chandler – You make an excellent point about parallelization – declarative code is much easier to parallelize! Thank you for your comment!

    Posted on 24-Apr-10 at 8:45 am | Permalink
  13. Sergey

    Andrew, it’s a very good article and I absolutely agree with you. I think that who are not agree with you should read very nice book “Functional Programming for the Real World with examples in F# and C# by Tomas Petricek and Jon Skeet” (yes, Jon Skeet) or just one chapter from this book “1.2 Functional programming by example” and they will change their mind very quickly :)

    Posted on 28-Apr-10 at 3:24 am | Permalink

One Trackback/Pingback

  1. [...] togaroga.com/2010/03/writing-better-code-its-imperative-that-you-are-declarative/ Posted in Random Geekiness by Edward Delaporte RSS 2.0 [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*