This post is inspired from a code review with a colleague, covering the many ways we, as c# developers, can write code to simply call a method three times.
Simplicity
You want to perform an action three times. You could just call the statement three times
Console.WriteLine("Hello Reader");
Console.WriteLine("Hello Reader");
Console.WriteLine("Hello Reader");
Chances are, this may make you twitch a little. It’s not DRY and not very scalable – you might chose to do something like this
public void DoSomething(int count) { for (int i = 0; i < count; i++) { Console.WriteLine("Hello Reader"); } }
What’s wrong with this? Nothing as far as the compiler is concerned and it will of course call your method three times (when a 3 is passed into the function). The picky part of me thinks this isn’t good enough though.
In particular, we wanted to call a method three times, so for this simple task why do we have to declare an integer? Why is it called ‘i’? Surely those days belong to the days of a fax machine?
C# is a pretty rich language. We can do better.
Who doesn’t love ForEach?
If I had a collection with three items, I could simply call ForEach, right?
private static void EnumerableRangeForEach(int count) { foreach (var number in Enumerable.Range(1, count)) { Console.WriteLine("Hello Reader"); } }
Looks a bit better, but I don’t need an ordered collection of integers really, just a collection with (3) things in it. Like this:
private static void EnumerableRepeatForEach(int count) { foreach (var item in Enumerable.Repeat(typeof(bool), count)) { Console.WriteLine("Hello Reader"); } }
At least our code doesn’t declare an ordered integer array now; now we have a collection of three booleans. However, we still have the annoyance of needing to declare var item to please the for loops gods. We can do away with the named variable (ish) if we add in the additional expense of converting it to a List
Enumerable.Repeat(typeof(bool), count) .ToList() .ForEach(item => Console.WriteLine("Hello Reader"));
Everyone loves a one liner. At least the author of it does, reading someone else’s isn’t always such a joy. My main concern is that we had to create a collection, then convert it to a list in order to iterate over it, using List’s .foreach extension.
Please the recursive gods
Many years ago, I had no beard and when not sleeping through lectures at university learnt to program, functionally. The lecturers in their wisdom thought functional programming was the way forwards and once upon a time I was proficient in ML (F# has some of its origins here) and Prolog. Naturally I used all these skills, when I started out as VB programmer after graduating…
I digress. Our desire to do something three times, can be written like.
private static void RecursiveLoop(int loopCount) { if (loopCount == 0) { return; } Console.WriteLine("Hello Reader"); var nextCount = loopCount - 1; RecursiveLoop(nextCount); }
Granted this isn’t the smallest method here. On the plus side, we are not forced to declare an implicit collection and we don’t have any variables that aren’t doing anything explicit. You can of course argue that we are still declaring a variable (nextCount) to keep track of where we are, similar to our var number sacrifice earlier.
If you are unfamiliar with recursive functions, I should point out that failure to declare a base case (if loopCount == 0 in our case) that will always be hit, will result in a StackOverflow. Similarly in some circumstances if you’re are looking at doing thousands of recursive calls and you are using tail recursion, then current limitations with the c# compiler will also result in a stackoverflow. Lots of posts about this on the web, this one ain’t bad: http://volgarev.me/blog/62412678347
What’s best
As ever in computing, it depends should be the right answer. If the business case strongly suggests that you only ever need to call something three times and it’s unlikely to change, I can see a case for the non dry example at the top. Very efficient and easy to read and I’ve seen code bases a lot worse in terms of dryness.
More realistically, this number three is likely to be changeable, so you want a collection and the ability to iterate over it. Personally I like the style of the recursive function and have some negative opinions on for (int i = 0; i< upperBound; i++) – just seems so primitive and unimaginative. However, the compiler’s going to reduce them to basically the same thing so as long as your method is clean, easy to read and easy to test, it’s all good.
What’s your preference?
Performance
Of course there’s a big except to my last paragraph. Not all for loops are the same when you really need to squeeze your method and get it crunching 1000s and every nano second counts. I’ll cover this in my next post.