Death to the IF statement

code 0 comments suggest edit

Over the past few years I’ve become more and more interested in functional programming concepts and the power, expressiveness, and elegance they hold.

But you don’t have to abandon your language of choice and wander the desert eating moths and preaching the gospel of F#,  Haskell, or Clojure to enjoy these benefits today!

In his blog post, Unconditional Programming, Michael Feathers ponders how less control structures lead to better code,

Control structures have been around nearly as long as programming but it’s hard for me to see them as more than an annoyance.  Over and over again, I find that better code has fewer if-statements, fewer switches, and fewer loops.  Often this happens because developers are using languages with better abstractions.  They aren’t consciously trying to avoid control structures but they do.

We don’t need to try and kill every if statement, but perhaps the more we do, the better our code becomes.

Msi_if_coverPhoto from wikimedia: Cover of If by the artist Mindless Self Indulgence

He then provides an example in Ruby of a padded “take” method.

…I needed to write a ‘take’ function to take elements from the beginning of an array.  Ruby already has a take function on Enumerable, but I needed to special behavior.  If the number of elements I needed was larger than the number of elements in the array, I needed to pad the remaining space in the resulting array with zeros.

I recommend reading his post. It’s quite interesting. At the risk of spoiling the punch line, here’s the before code which makes use of a conditional…

  def padded_take ary, n
    if n <= ary.length
      ary.take(n)
    else
      ary + [0] * (n - ary.length)
  end
  end

… and here is the after code without the conditional. In this case, he pads the source array with just enough elements as needed and then does the take.

  def pad ary, n
    pad_length = [0, n - ary.length].max
    ary + [0] * pad_length
  end

  def padded_take ary, n
    pad(ary, n).take(n)
  end

I thought it would be interesting to translate the after code to C#. One thing to note about the Ruby code is that it always allocates a new array whether it’s needed or not.

Now, I haven’t done any benchmarks on it so I have no idea if that’s bad or not compared to how often the code is called etc. But it occurred to me that we could use lazy evaluation in C# and completely circumvent the need to allocate a new array while still being expressive and elegant.

I decided to write it as an extension method (I guess that’s similar to a Mixin for you Ruby folks?).

public static IEnumerable<T> PaddedTake<T>(
  this IEnumerable<T> source, int count)
{
  return source
    .Concat(Enumerable.Repeat(default(T), count))
    .Take(count);
}

This code takes advantage of some Linq methods. The important thing to note is that Concat and Repeat are lazily evaluated. That’s why I didn’t need to do any math to figure out the difference in length between the source array and the the take count.

I just passed the total count we want to take to Repeat. Since Repeat is lazy, we could pass in int.MaxValue if we wanted to get all crazy up in here. I just passed in count as it will always be enough and I like to play it safe.

Now my Ruby friends at work might scoff at all those angle brackets and parentheses in the code, but you have to admit that it’s an elegant solution to the original problem.

Here is a test to demonstrate usage and show it works.

var items = new[] {1, 2, 3};

var result = items.PaddedTake(5).ToArray();

Assert.Equal(5, result.Length);
Assert.Equal(1, result[0]);
Assert.Equal(2, result[1]);
Assert.Equal(3, result[2]);
Assert.Equal(0, result[3]);
Assert.Equal(0, result[4]);

I also ran some quick perf tests on it comparing PaddedTake to the built in Take . PaddedTake is a tiny bit slower, but the amount is like the extra light cast by a firefly at noon of a sunny day. The performance of this method is way more affected by the number of elements in the array and the number of elements you are taking. But in my tests, the performance of PaddedTake stays pretty close to Take as we grow the array and the take.

I think it’d be interesting to have a build task that reported back the number of `if` statements and other control structures per line of code and see if you can bring that down over time. In any case, I hope this helps you improve your own code!

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

116 responses

  1. Avatar for jbblanchet
    jbblanchet November 8th, 2013

    The Ruby solution is elegant (heck I'm a c# guy and even I understand it). The c# one feels both contrived and unnecessarily obscure. There's no way to understand at a glance, which you would do with the if statement. There's no way I'd let such code pass review. Let's not fall into the trap of getting rid of keywords for the sake of it. This is, in my opinion, an inelegant solution to an unexisting problem.

  2. Avatar for Smirker
    Smirker November 8th, 2013

    This is horrendous. In the first example, you can't sanely purport that using "max" reduces your dependence on "if." That "if" statement is tucked away in there.

    People should focus on writing readable code where possible, not confusing, keyword-sparse gymnastics.

  3. Avatar for distantcam
    distantcam November 8th, 2013

    I disagree. In C# land take is part of the LINQ ecosystem. When creating a similar method I would reach for LINQ methods before writing one by hand. Otherwise you'll miss out on things like lazy evaluation. I would fail the first code with the if and say that it has to be lazy.

  4. Avatar for distantcam
    distantcam November 8th, 2013

    Of course you've simply buried the if statement down in the original take, so it's still there, just hidden. :P

  5. Avatar for Chris Hynes
    Chris Hynes November 8th, 2013

    Or you could make the operation composable, a la:

    public IEnumerable<t> PadEnd<t>(this IEnumerable<t> values, T padValue = default(T))
    {
    foreach (T value in values)
    yield return value;

    yield return padValue;
    }

    And then you can call it like:

    var items = new[] {1, 2, 3};

    var result = items.PadEnd(0).Take(5).ToArray();

    IMHO, much more readable and more in the spirit of LINQ.

  6. Avatar for haacked
    haacked November 8th, 2013

    The point is that the code that _you_ maintain does not have the control structure and is thus more declarative and expressive.

  7. Avatar for haacked
    haacked November 8th, 2013

    Sure, but you don't need to maintain that code. You maintain the code you write which does not have the "if".

  8. Avatar for jbblanchet
    jbblanchet November 8th, 2013

    "I would fail the first code [...] and say that it has to be lazy."

    Why? Give me a single reason why "it has to be". It's slower, murkier code. "Lazy" here serves no purpose since the if would not create an object if it isn't needed.

    By the way, I'm not advocating against the use of take or for reinventing the wheel. I'm not saying to put if everywhere either. I'm simply arguing that code should be kept simple instead of religious.

  9. Avatar for haacked
    haacked November 8th, 2013

    I disagree. These are standard LINQ operators that anyone who's spent any time with them would understand.

    After all, I just combined his two methods into one. I could have made the Concat+Repeat call into its own method called Pad and the code would be essentially the same as the ruby code, but probably with better performance.

  10. Avatar for haacked
    haacked November 8th, 2013

    Your implementation is incorrect. It's only going to pad the sequence with one value.

    Why not just implement PadEnd in terms of existing LINQ operatorns?

    public static IEnumerable<t>(this IEnumerable<t> source, T padValue = default(T))
    {
    return source.Concat(Enumerable.Repeat(padValue, int.MaxValue));
    }

    Look familiar?

  11. Avatar for jbblanchet
    jbblanchet November 8th, 2013

    I'll disagree with myself right here. You mean "as an extension method for IEnumerable it has to be lazy", and with that I totally agree. Now that's a great reason to ditch the if. Sorry about my misunderstaning your point distantcam.

  12. Avatar for Chris Hynes
    Chris Hynes November 8th, 2013

    Sorry, I missed one line. Should have been:

    public IEnumerable<t> PadEnd<t>(this IEnumerable<t> values, T padValue = default(T))
    {
    foreach (T value in values)
    yield return value;

    while (true)
    yield return padValue;
    }

    ;-)

    Which, I suppose, ends up being the same as using concat/repeat. Can't break myself out of the old procedural habits, can I?

  13. Avatar for haacked
    haacked November 8th, 2013

    Bingo! :)

  14. Avatar for Rick Woodlands
    Rick Woodlands November 8th, 2013

    Could you point me to some articles about Linq Query evaluation. Having hard time to get my head around the lazy part.

  15. Avatar for Frank Quednau
    Frank Quednau November 8th, 2013

    I think the "play it safe" part is what makes this code less elegant than it can be as providing the count to repeat forces you to think about why count is passed. Of course your reasoning about it is correct, but the fact that reasoning was necessary makes this a bit ad-hoc.

    Provided that you already have a repeat extension method without count that repeats indefinitely, i.e. without the weird artefact from times of imperative code, the line simply reads

    elements.Concat(default(T).Repeat()).Take(count).

  16. Avatar for Alenas
    Alenas November 9th, 2013

    This example has nothing to do with "the death of if". The first code with "if" is just OK written code, as it is not optimal. If we compare OK code with GOOD code, then there always be a difference - both in performance and readability. I don't see a reason to encourage developers to think about "IF's", when they should be thinking about optimal execution.

  17. Avatar for Tomáš Pažourek
    Tomáš Pažourek November 9th, 2013

    Hi, I recently started to develop a set of extensions, that should help extend the declarative capabilities of C#. I would love to hear any feedback, the code is in very early stage of development (just a few commits).
    Here: https://github.com/tompazou...

  18. Avatar for waynewerner
    waynewerner November 9th, 2013

    Personally, I want my developers thinking about the optimal execution on the correct machine: themselves.

    If it turns out that we need more power, then lets see if we can throw machines at it. And if not *then* we'll start looking at developer cycles.

  19. Avatar for Alenas
    Alenas November 9th, 2013

    I guess you did not understand what I mean. I will try to illustrate.
    If you read the description of the problem, then it says "...If the number of elements I needed was larger than the number of elements in the array, I needed to pad the remaining space in the resulting array with zeros...".
    Logical interpretation of that, is to a) take an array elements and b) pad remaining space.
    So the first sample code does not solve the problem in a way it was described. It means developer was not thinking about the problem and was not putting effort into understanding the problem - up to you if you are happy with a code which is hard to understand...

  20. Avatar for Alenas
    Alenas November 9th, 2013

    It is a very well known fact, that you can't throw more hardware at a shitty code.

  21. Avatar for Cristóbal Galleguillos Katz
    Cristóbal Galleguillos Katz November 9th, 2013

    The metric you propose to track in your last paragraph sounds like cyclomatic complexity. Visual Studio Code Metrics PowerTool calculates it, you can use it in your build task maybe.

  22. Avatar for Artëm Smirnov
    Artëm Smirnov November 9th, 2013

    If "maintaining" means looking at the code a year after I wrote it and immediately understanding what's going on, I'd choose the first (Ruby) version. One more if statement, but one less function to maintain.

  23. Avatar for haacked
    haacked November 9th, 2013

    Right. Original implementation with the "if" is telling the computer what to do. The latter implementation is more about telling the computer what you want.

    It's like the difference between "Go north 100 steps, Go east 50 steps, Go North another 100 steps." instead of "Go to the store." I prefer declarative code.

  24. Avatar for haacked
    haacked November 9th, 2013

    It's not quite the same. I'm thinking of the total # of ifs in a project. If I have one "if" per method, my cyclometric complexity will remain low, but I'll have a lot of ifs still. That's not as bad as having a bunch of methods with cyclometric complexity, but it still might indicate I need to try and be more declarative. :)

  25. Avatar for Marcel Popescu
    Marcel Popescu November 10th, 2013

    This. "Concatenate the initial array with a list of zeroes, take the first n elements of the result" is at a higher level of abstraction than if/for.

    The most well-known example of a declarative language is, I think, SQL. SELECT * FROM Employees WHERE ManagerId = 5 is much, much easier to understand *and maintain* than a for loop with an if statement inside it would be.

  26. Avatar for martijnhoekstra
    martijnhoekstra November 10th, 2013

    while I agree with your general point, I think the example where you take n items with a default if there aren't n items in the collection is a bit of a code smell, and takes away from your central point. I can't really think of a good reason why you'd want to do that.

  27. Avatar for Me
    Me November 11th, 2013

    Fantastic! You can push the if statement into the framework!

  28. Avatar for Jivko ILYEV
    Jivko ILYEV November 11th, 2013

    I agree with your reasoning, I have one question thou. Why don't you use math to extend the list only with the right number of entries. Concat and Repeat are lazy methods, that's fine, but how are you sure there are no extra entries added?

  29. Avatar for Alejandro Varela
    Alejandro Varela November 11th, 2013

    totally agree, performance is horrendous too...
    don't get me wrong, i like higuer order functions and all of the functional programming.
    but..... when a simple if can do the work i prefer the if.
    real functional languages like haskell, scheme | lisp, __do have__ the "if" statement.
    http://www.haskell.org/hask...

  30. Avatar for Alejandro Varela
    Alejandro Varela November 11th, 2013

    haskell "if"
    http://www.haskell.org/hask...
    scheme "if"
    http://docs.racket-lang.org...
    F# "if"
    http://msdn.microsoft.com/e...
    and yes, they are functional languages...

  31. Avatar for Claude "CodeAngry" Adrian
    Claude "CodeAngry" Adrian November 11th, 2013

    if(you got no code to write){
    write pointless posts like this;
    }else{
    do something useful with your time;
    }
    Kids writing code these days... (sigh) It has to be declarative, expressive, use patterns (whether it's necessary or not), purely functional or purely OOP... and all the buzzwords that will render their code uselessly unmaintainable in the shortest time.
    If I were to handle code written by the OP here, I'd quit my job... instead of digging within the codebase just to see where the IF actually is. And I write native C++ myself... I'm not easily intimidated.
    PS: There's is nothing more expressive than an IF (in programming or life)... as everybody likes choices.
    PPS: CodeProject.com's newsletter pointed me here. It really starts to resemble a gossip magazine. I'll soon unsubscribe IF it keeps up, even IF I've been with them for over a decade. - how expressive I was using IFs ;)

  32. Avatar for AlbertoMonteiro
    AlbertoMonteiro November 11th, 2013

    How about

    public static class Extencoes
    {
    public static IEnumerable<t> PaddedTake<t>(this IEnumerable<t> source, int count)
    {
    return source.Concat(Enumerable.Repeat(default(T), Math.Max(0, -(source.Count() - count)))).Take(count);
    }
    }

  33. Avatar for Paul Barrass
    Paul Barrass November 11th, 2013

    I was also sent here by CodeProject, and I agree with every point you make. This propensity towards higher level abstraction for EVERYTHING, rather than just where it is applicable to a particular problem domain is a terrible waste of time.

    (The rest of this post is for the original author)

    Not only that, but an IF (Or at least the conditional operator, including the ternary ?), particularly in C++ is the expressive distillation of selection. One of the three primitive operations of all languages (Sequence, selection, iteration) since time began, and is useful, not only because it allows us to deal with the unknown or unwanted at runtime, but also because of it's closeness to the wire. The Ternary operator code in C++ is compiled to blindingly fast machine code for example.

    Removing selection (Which in some cases is a good idea, after all, polymorphism came about because everyone was fed up of those damn CASE statements littering every sub program we ever had to write) entirely for the purposes of creating better code is a misconception at best, and positively bad practice at worst.

    The author of the quoted article also fails to make his point adequately, and instead of this type of recycling, I suggest you read some Booch, Jacobbsen, or, even the Gang Of Four patterns book, which is almost full of patterns where polymorphic hierarchies orthogonal to one another help to eliminate the kind of control structure which is eminently bad, rather than trying to eliminate genuinely useful conditional code.
    As an aside, I wonder how many C++ programmers would share our view. Obviously, the language in question plays a large part, and when I read the above example, I just implement a std Vector with a conditional (If vector.size < n) resize (n) in advance of use, but because I know that this is an expensive operation if the Vector's capacity is exceeded by the resize, I avoid it wherever possible.
    Will be checking back to see what other's think, and regardless of anything else, keep posting. Debate worthy content on the internet is always a great thing, particularly when it extends to more than 140 characters.......

  34. Avatar for Paul Barrass
    Paul Barrass November 11th, 2013

    This is true, only when dealing with a given problem domain, which is not when the author of this or the quoted article actually say though. Everyone agrees that declarative and functional programming really scratches the spot when it comes to being easier to pick up for the novice, easier to maintain a full vocabulary of any given domain, and generally less demanding to the human brain in dealing with syntactic idiosyncrasies, but to offer up the opinion that conditions make code inherently worse, and that they should be optimised away is surely not right?

  35. Avatar for Tyler Bindon
    Tyler Bindon November 11th, 2013

    Take a look at McCabe's Cyclomatic Complexity. It formalizes the measurement of control structures in code.

  36. Avatar for Marcel Popescu
    Marcel Popescu November 11th, 2013

    I think this is a subset of a more general rule: prefer abstractions. The "if"s and "for"s are details of implementation; just as

    var list = new List<int>();
    for (var i = 0; i < 5; i++)
    list.Add(i);

    can be simplified to

    var list = Enumerable.Range(0, 5).ToList();

    (thus removing the "for" statement as an implementation detail - it's still there, but hidden behind abstractions), so can the "if" in the original problem be abstracted away. The result is that you're expressing the so-called business logic, the actual problem you're interested in (pad an array with zeroes) instead of the concrete details of how to accomplish that.

  37. Avatar for Anonymous
    Anonymous November 11th, 2013

    "By the way, I'm not advocating against the use of take or for reinventing the wheel. I'm not saying to put if everywhere either. I'm simply arguing that code should be kept simple instead of religious."

    I totally agree with the above statement. I much rather have code I can read 2am in the morning half sleep than code I have to translate. If statements are natural.

  38. Avatar for Alex Burke
    Alex Burke November 11th, 2013

    You cant optimise though. If you are using functions that are essentially 'black boxes' you have no idea what they are doing, so yes you can maintain your code easier but you are trusting that the person who wrote the original function wrote it a) properly or b) with your algorithm in mind (trade off mem vs proc vs storage vs accuracy of implementation). I mistrust libraries for this very reason and if implementing exceptionally heavy lifting algos will write from scratch - down at asm level the IF is a comparisor + branching instruction anyhow so you cant get away from them IMHO. Why would you want to? My passion is solving programmatical problems with the best fit solution not play with Lego and write two lines of cludge that if the implementation of the relied on function changes, or platform dependant bugs, I end up having to write it myself anyway. If its easy its cos you're doing it wrong.

  39. Avatar for Alanna Muir
    Alanna Muir November 11th, 2013

    In some cases, using higher level metaphors for programming can improve performance as you're utilizing the low-level preprogrammed implementation as apposed to your version that will run in CIL/LLVM/Java/etc. For example, the writer basically replaced the IF with MAX; we know in C/C++ that these are equivalent (and often IF will be faster than MAX when we only need a partial evaluation), but in C# et al, this may not be the case, as the implementation of MAX might be more optimized than your code running through the JIT compiler.

    But I agree, that's beside the point. Not only does this fall into the category of micro optimization (perhaps it's not the best example), but I find the abstraction less clear than the original code. Maybe I'm used to booleans and relational operators, and have no love for LINQ and other "BASIC" and "SQL" like add-ons to C#/Java, but that MAX operator is rather buried at the end of the line. The most important aspect is at the end, and I think that's wrong. The most important aspect of this routine is to guard against a too-short list length, so that should be first and foremost. The IF clearly demonstrates this.

  40. Avatar for Alex Burke
    Alex Burke November 11th, 2013

    Same as CodeProject and C++. I agree with you. Closeness to the wire is an amazingly apt expression. My thoughts after the rage dissipated were apart from the obvious replace everything with a function and who cares what the function actually does right?! Coding is an artform and getting rid of bare bones conditional branching just because the text looks ugly or because im too much of a tight arse to maintain my own code or at least the bits that resemble programming and not extraction upon extraction and lots of .() but know knowledge, homage, reverence to the actual algo working away underneath it all. ANYBODY can type code into a page, five minutes on Stack overflow and a liberal copy paste and anybody can make anything work. BUT working is not the point (at least not for me) it should be elegant yes, but in a logical sense not creating wasteful iterations, optimal design in memory and processor during runtime not in compilation. Optimising isn't having 200 lines of code rather than 2000 just because it 'looks nicer that way'. Well written, well designed, carefully crafted (and usefully commented) code is a thing of beauty not the size of it or how the syntax looks. Anyways I ramble. Maybe i just love the if statement too much..

  41. Avatar for Alex Burke
    Alex Burke November 11th, 2013

    Should have been "during runtime and not *just in compilation" and "no knowledge" not "know knowledge" Apologies, my spelling, punctuation and grammar went to pot. Overexcited - it is a good debate though...

  42. Avatar for Alanna Muir
    Alanna Muir November 11th, 2013

    Conditional branching is the most costly operation a processor can undertake. Intel has spent billions optimizing their branch prediction and even today, a large amount of chip real-estate is dedicated to branch prediction. Jumps, however, are absolute and cost very little, even if they are subroutine calls. So the elimination of branches is a very valuable thing. On x86 processors, there are integer and floating point MAX operators that pose no risk of cache faults or mis-prediction penalties. Now, whether the CIL can generate SIMD instructions in cases like this to optimize out both the branch and subroutine call, I don't know.

  43. Avatar for Alex Burke
    Alex Burke November 11th, 2013

    Absolutely agree - I was meaning in response to the examples given in the post. Of course ternaries, binary ops and generally thinking about what each cycle of your code is doing cuts out massively wasteful/unnecessary branching and for that I stand corrected (blindsided if you will). It was more the functional wrapper approach and the offloading of maintenance issue and blindness to what was happening lower down. Sometimes an If -> else if -> else is the absolute best fit for the algo if you cant perform it with one of the above mentioned approaches. Im not aware of how a programmer specifically can utilise said branch predictions from the chip mind you (in a higher level language not asm) ? and if the prediction is wrong doesnt the chip hang for the next proc cycle? sometimes negating the benefit of the prediction in the first place? I mean by all means replace a very long if with a switch - architecturally though thats why one would dive into asm and optimise from there - granted its totally platform dependant and most compilers these days do a pretty good job - so unless the function you are calling is some form of trustworthy platform agnostic asm routine isnt the branch prediction somewhat hit and miss and not really relevant to what a coder is doing in a higher language abstraction? forgive me if i'm off base?

  44. Avatar for Artëm Smirnov
    Artëm Smirnov November 11th, 2013

    Why is everybody discussing performance? The author never claimed that the improved version was performing better, only that it's easier to maintain.

  45. Avatar for Cenorios
    Cenorios November 11th, 2013

    In the ruby example, how about:

    def padded_take ary, n
    y = [0] * n
    y[0..ary.length-1] = ary.take(n)
    return y
    end

    You avoid the if, max, and creating an array when it is not necessary!

  46. Avatar for H.M. Müller
    H.M. Müller November 11th, 2013

    Being a mathematics aficionado, I also like these "elegant", "decision-less" solutions.

    HOWEVER, I have found out that when thinking about such algorithms, almost always we (all stakeholders in the code: analysts, testers, and also these lowly programmers) argue by cases: "Let's assume the list is longer, then ...; but if it is shorter, then ...".

    And all the (unit and other) tests done will also do this.

    So my experience is that you have gained nothing - nothing at all; and the risk is HIGHER that maintenance introduces errors because each change "changes all cases together".

    Yes, if someone writes code where ONLY the cases that behave VERY SIMILARLY are grouped together with such ideas, THEN the code really becomes much better to maintain (I hesitate to write "easier to maintain" ...).

    But if the grouping becomes like tricky like in the original example (where the max is just another "case-distinguishing operator", i.e., something, which exactly the same amount of "think time" as an if), then the maintainers will curse you more ....

    ----------

    A special case: In PASCAL (my first language) and all later languages, you can write

    boolVar := a > b;

    For a long time I and many other "advanced" guys laughed at the people who wrote

    IF a > b
    THEN boolVar := TRUE
    ELSE boolVar := FALSE;

    However, after having worked (and instructed) larger teams, I found that the latter allows you do add comments "at the right place":

    IF a > b
    (* This is the usual case when the user does this and that ... *)
    THEN boolVar := TRUE
    (* Only when that funny things happens, we arrive at this place; this has a few consequences downstream, namely ... *)
    ELSE boolVar := FALSE;

    This structure is lost in the "elegant", IF-less formulation ...

    =======

    Nevertheless, refactorings like "replace cases with polymorphism" and also "replace cases with encompassing algorithm" (as in the article) are valuable tools of the trade ...

    H.M.M.

  47. Avatar for Alanna Muir
    Alanna Muir November 11th, 2013

    Because I believe the paradigm of code refactoring is born from the problem of coders always wanting to code from scratch. We presume that writing code from foundation is going to be more optimized than the "black boxes" which we cannot control. In the era of intermediate code and JIT compilation, this is seldom the case, and more often than not, the higher level abstractions can perform better than had we written new code from scratch.

    That's not to say that it's not also more manageable code. It's always going to be easier to target .Net framework functions than reinvent the wheel and have thousands of lines of my own implementation that does more or less the same thing, slower.

    In a nutshell, the lesson should be that knowing the keywords and syntax for a language is not as important as having a concrete understanding of the framework you have at your dispense. Gone are the days of the dangerous and slow (strlen anyone?) C Standard Library, and if you're writing everything from scratch, you're not a very efficient programmer.

    Now, I spend half my time in embedded C world, where the opposite is true. Compilers are sometimes an afterthought of microcontroller vendors and seldom do I see the level of optimization that exists in the x86 world. Nor is there any intermediate level, I'm writing what amounts to a small abstraction from assembly language, so code is likely as, if not more performant that the more generic code available in the standard libraries. So these ideas aren't universal, and I disagree with them being taught in Universities as a tautology.

  48. Avatar for Bopdji Shah
    Bopdji Shah November 11th, 2013

    Quite frankly, all CPUs have conditional branches at the machine language level. I do not see any reason at all to get rid of conditional statements in so called "higher languages"

  49. Avatar for George
    George November 11th, 2013

    Conditional (IF) and assignment (=) are the 2 major things that distinguish programming from abstract mathematics. Do not forget that a CPU does not have control structures like FOR, WHILE etc., only MOV, JMP, CALL, and JMP on CONDITION.

  50. Avatar for Alex Burke
    Alex Burke November 11th, 2013

    Actually I've thought about this alot and actually I think I responded in haste. Conditional branching is costly if the branching was unnecessary in the first place. I don't see how you can get around it though (JZ,JNZ,JAE,JBE,JNLI all have a logical comparison component) and there are far more costly operations the x86 can perform depending largely on the available instructons sets/opcodes.

    The trouble is it all depends on what language, platform you are on as to what is the best solution and you make a point about the orig C function strlen(), however where i widely disagree is the fact that in its original intent, the programmer was supposed to KNOW it wasnt a memory safe operation. All you have as an improvement is to insert into the function a length parameter ergo a conditional branch (a few actually jmp if zero, jmp if larger than you max container, JLE etc) which depending on what you are TRYING to do affects how optimised you need it to be and adds cycles to the process time. I like the old implementation not because it is unforgiving but i feel it does lead to better design choices - precheck/assert before you use it etc or fixed length buffers that dont need the extra checks - every other variant is doing it for you which is fine if you don't care about the overhead. To not inform people there is a distinction is wrong.

    The caveat to that is the more platforms you use, languages etc you form an idea/palette of choices about which library platform functions are typesafe/memsafe/not buggy or even vendor safe and also best fit for the problem you are given and the limitations of your brief etc.

    Nobody said you HAVE to write everything yourself as that is inefficient, however I'd rather teach there is a rule that has exceptions, that inform design choices and implementations, rather than just brush over it with you don't need to know how it works because microsoft wrote all .NETs functions perfectly. (Or suns java functions or dammit apples NS functions. Jesus some win32 functions actually have handles for things that weren't ever implemented not to mention undocumented opcodes on chips ala the 6502)

  51. Avatar for Michael Amann
    Michael Amann November 11th, 2013

    OMG, "less control structures?" Fewer control structures!!!!

  52. Avatar for Alanna Muir
    Alanna Muir November 11th, 2013

    Long live unit testing!

    But the case of buggy frameworks comes down to this; do you write it yourself and hope to do better than the designers, or take their word for it that all is well. I think either way, you're bound to be revisiting the code down the road, and either you're fixing your own code (or worse, someone else's), or you're replacing the library. I think generally the latter is preferable and a little homework beforehand can help minimize these risks.

    With the branch prediction thing; I might have over specified my position. The slowest action the CPU has to take is to fetch data from DRAM. Compared to the CPU this can be hundreds of cycles. Branches and random data fetches are both prone to cache misses, and modern CPUs try to mitigate this as mush as possible, but if the developer has a good strategy for minimizing this risk, then all the better.

  53. Avatar for Rick
    Rick November 11th, 2013

    LOOP, REP(NE/E)?

  54. Avatar for OldTimerSteve
    OldTimerSteve November 11th, 2013

    Interesting discussion. I'd vote for the clarity of the "if" - except that in C# in particular the whole exercise is moot. Arrays are initialized to "0" by default and can be reset using Array.Clear. This is a simple mem op with little overhead. Also, once the compiler gets at it the "if" structure is optimized and runs like lightning too - moreover, iterative "if", "while" "for" and "foreach" structures all resolve to similar machine code, as does the enumerator of IEnumerable. Come to think of it, so does moving all zeroes to a chunk of memory. Initialize the array to zero, and use whatever you like - but for gosh sake make it understandable to the next developer who needs to read it.

  55. Avatar for Stephen Hammond
    Stephen Hammond November 11th, 2013

    There seem to be a lot of folks who disagree with reducing the use of "if" statements. I think this is because the "if" statement is one of the first lessons in programming. But what would happen if we applied this same rule to "lock"? The value of code that is read as intended starts to multiply.

  56. Avatar for haacked
    haacked November 11th, 2013

    You'd have to ask the author of the post I referred to for why. But I can think of scenarios. Perhaps he needs to do some operation on two arrays that's simpler if they're the same length.

  57. Avatar for haacked
    haacked November 11th, 2013

    > but how are you sure there are no extra entries added?

    That's the definition of lazy. Under the hood, the Enumerate and Concat methods use the iterator pattern. They only yield the values pulled. http://msdn.microsoft.com/e...

  58. Avatar for haacked
    haacked November 11th, 2013

    Yeah, despite the title of my post, I'm not actually advocating the death of all "if" statements. Just thoughtful use of them.

  59. Avatar for Alejandro Varela
    Alejandro Varela November 11th, 2013

    i agree with you, sometimes functional style is much better, sometimes don't, thanks for the post and sorry for my awfull english! :)

  60. Avatar for haacked
    haacked November 11th, 2013

    Your code has a flaw. It presents a false dichotomy. See, only one if statement in your comment and you got it wrong. :P

    > Kids writing code these day.

    Ha, I haven't been called a "Kid" in a long time. I'm sure Michael Feathers isn't a kid. The usual reason to resort to an ad-hominem is in lieu of an actual strong argument.

    > instead of digging within the codebase just to see where the IF actually is.

    Even in C++ you're dealing with a level of abstraction. There's a point where you're willing the computer to just do something and not feel you have to tell it exactly how to do it.

    For example, when you tell the computer to print something to the screen, you don't tell it "IF there's enough memory available for this string, allocate the necessary memory. IF a display is available and IF the device driver is ready, send this string to the driver to display it." And so on...

    Even a printf statement hides a lot of "IF" statements. "printf" is declarative. You declare that you want the computer to print something, and _it_ figures out all that needs to happen to do that. *Your* code doesn't have to bother with that every time yo uwant to print something to the screen.

    *THAT* is what this post is about. Looking for ways to make your code more declarative so that you can tell the computer *what* you want rather than having to tell it *how* every time.

  61. Avatar for haacked
    haacked November 11th, 2013

    I'm actually a big fan of the ternary operator. It's more declarative than an if statement. Typically, a ternary operator is used to return a value based on a condition. It doesn't branch lines of control.

  62. Avatar for haacked
    haacked November 11th, 2013

    > but to offer up the opinion that conditions make code inherently worse, and that they should be optimised away is surely not right?

    I never said that. We're talking about branching control structures. Not conditionals.

    For example, I have no problems with ternary operators.

    ```
    var foo = someCondition ? value1 : value2;
    ```

    That's a conditional, but it returns a value rather than creating a branch in the code execution.

    Also, despite the sensationalistic title, I don't advocate for the death of all "if" statements. I'm just advocating more discretion in using "if" for branching control.

  63. Avatar for haacked
    haacked November 11th, 2013

    Yeah, that is definitely safe too. But I think having a `Repeat()` method is a bit dangerous because someone somewhere will inadverdently call `ToArray` on it. ;P

    I'd rather cap the damage that can be done if that happens.

  64. Avatar for haacked
    haacked November 11th, 2013

    This is not a query evaluation as much as examples of the iterator pattern. http://msdn.microsoft.com/e...

  65. Avatar for martijnhoekstra
    martijnhoekstra November 11th, 2013

    I agree that there are algorithms (like one you propose, where you might want to step through two collections in lock step) that are easier solved with two collections with the same amount of elements in them, but the central issue here is that apparently you don't have those here. It reminds me somewhat of the joke with the chemist, physicist and economist on the deserted island. The chemist proposes to use the local plants to make a fire that will produce a lot of black smoke, hopefully attracting the attention of a passing ship. The phycicist proposes a system of mirrors to signal for help. The economist begins "well, if we assume we have a boat...". If you need to pad your list, your actual problem to be solved is up the stack, and padding it is probably not the cleanest solution. If you are using the padded elements as a signal function, you are pushing an if statement up the stack. If you are padding with an identity element for some operation, you need to know which operation to know which element is identity, and that too is probably better solved up the stack close to the actual operation.

  66. Avatar for martijnhoekstra
    martijnhoekstra November 11th, 2013

    unfortunately, the ternary operator is very difficult to use when their bodies are larger than a simple expression.

    Action _true = () => { some; logic; that; produces; a; return value;};
    Action _false = () => { some; different; logic, that; produces; a; different; return value; };

    var foo = someCondition ? _true() : _false();

    is, I'm sure we can all agree, quite horrid.

  67. Avatar for martijnhoekstra
    martijnhoekstra November 11th, 2013

    none of those are if statements, but if expressions, akin to the ternary operator in C#. The diffence is they produce a value without causing side effects.

  68. Avatar for haacked
    haacked November 11th, 2013

    Given I didn't have the full context of the original problem, I had to take it at face value that there's a good reason to pad the array.

    And given that, I still think it's a good case for a more declarative approach than an imperative approach.

    Rather than tell the computer how to pad a list, I focus more on telling it what I want and letting it figure it out.

    This is a simplistic example to demonstrate the concept.

  69. Avatar for Alejandro Varela
    Alejandro Varela November 11th, 2013

    yes, those are expressions, but i can't see what side effect would cause an if statement (in a language like c#), can you explain?

  70. Avatar for martijnhoekstra
    martijnhoekstra November 11th, 2013

    an if statement in a language like C# can only funcion because of side effects. The code taken in the if branch must have an effect on something outside the if body to have any visible effect. That can be IO, or mutating state outside the if body. The mutations here increase coupling and makes your code harder to reason about. Maybe if I'm failing to convey the idea, you could give an example of an if statement in c# that does something so I can show you what I mean, and where the side effects are.

  71. Avatar for haacked
    haacked November 11th, 2013

    I think this was addressed better in the blog post I linked to better than I could express. :)

  72. Avatar for Guest
    Guest November 11th, 2013

    an example...

    string something (int number) {
    if (number > 17)
    return "lala";
    else

    return "lolo";

    }

    i can't see where is the side effect here.

  73. Avatar for Alejandro Varela
    Alejandro Varela November 11th, 2013

    an example...

    string something (int number) {
    if (number > 17)
    return "lala";
    else
    return "lolo";
    }

  74. Avatar for martijnhoekstra
    martijnhoekstra November 11th, 2013

    terminating the current function with a return value definitely is a side effect. The extra cognitive overhead here is keeping track of the early returns. In the trivial example here it's not all that bad, but still not as easily comprehended as (pseudocode if expression )

    string something (int number) {
    return if (number > 17) {
    "lala";
    } else {
    "lolo";
    }
    }

    something as simple as this should obviously be done with a ternary operator though (which is an if expression)

  75. Avatar for Frank Quednau
    Frank Quednau November 11th, 2013

    the count on repeat is unnatural in the context of IEnumerables - indeed an IEnumerable has no notion of count or finiteness. Any ToArray, executed on some Entity Query or whatever underlying expression interpreter is running, can wreak havoc in your AppDomain. It is good to shield your fellow devs from harm, but in my opinion this should not come at the cost of expressiveness.

  76. Avatar for martijnhoekstra
    martijnhoekstra November 11th, 2013

    urgh, I replied to your logged out version, which is now gone.

    EDIT: No I/you didn't. I just guess disqus is too complicated for me, which doesn't bode well for my argument ;)

    Terminating a function with a return value is a side effect. The reason why that possibly introduces problems is that it gives you extra cognitive overhead on keeping track off what conditions need to be fulfilled for you are to be still inside your function body. In this case that obviously doesn't matter much, it's far too simple for that to be problematic. It is still expressed clearer with an if expression. For something as simple as the above, it can be done with the C# ternary operator, which is an if expression:

    string something (int number) {
    return (number > 17) ? "lala" : "lolo";
    }

  77. Avatar for OldSchooler
    OldSchooler November 11th, 2013

    I'm a financial engineer that uses C# and Fortran (I know). My programs are small (<30000 lines). I use IF all the time and love it. That's some reality from Hacksterville.

  78. Avatar for Dan Sutton
    Dan Sutton November 11th, 2013

    The main problem with this sort of thing (apart from it making the code mostly write-only) is that removing the If and replacing it with a generalized routine will, in most cases, slow down the code abominably. Whereas the default case for the If is a simple thing which requires only a few machine cycles, the superposition of a Linq-style query over it will create a bottleneck that's absolutely unnecessary. Sometimes, elegance is doing the obvious: I can't see a real programmer arguing that this type of thing makes anything better. Sorry...

  79. Avatar for martijnhoekstra
    martijnhoekstra November 11th, 2013

    For fun[citation needed] and profit[citation needed], I reimplemented this in idiomatic(tm) C#. For the complete horror, see https://gist.github.com/mar...

  80. Avatar for Jordan
    Jordan November 11th, 2013

    Did Yoda write your test? :)

  81. Avatar for Andy Wilkinson
    Andy Wilkinson November 11th, 2013

    Before I start I will openly admit that I am being picky with terminology here, but I'm not sure the comparison with "functional" programming is really correct. I would argue that we are really talking here about the difference between "declarative" and "imperative" approaches instead.

    In my experience functional programming tends to favour pattern matching which ultimately is a super powerful 'if' statement. If I was to rewrite the padded take in C# in a functional style then I'd propose something like,

    public static ImmutableLinkedList<t> PaddedTake<t>(
    this ImmutableLinkedList<t> source, int count)
    {
    if (count == 0)
    return ImmutableLinkedList<t>.Empty;
    else if (source.IsEmpty)
    return PaddedTake<t>(source, count-1).Add(default(T));
    else
    return source.HeadList.Add(PaddedTake<t>(source.Tail, count-1));
    }

    Note that this uses a (hypothetical) linked list implementation as often observed in functional programming and makes heavy use of recursion. In reality C# quickly heads towards stack overflow exceptions with this (which is why F# correctly implements tail-recursion(.

    This doesn't mean that the "declarative" approach discussed above is less powerful, in fact I'm a big fan of moving away from imperative logic and I would suggest the implementation I've given above isn't the easiest to understand... (I did say I was being picky didn't I?!)

  82. Avatar for richardjking2000
    richardjking2000 November 11th, 2013

    There is a dark side to this that is hidden because of the simplicity of the example, but becomes very much a difficult thing to get past in code written for significantly sized systems.

    By creating two different 'routines' to make up for the lack of if (or switch or whatever), you create no requirement for the code to reside anywhere near each other. And when that isn't a requirement, you'll get code spread all over the place (I know.. 30 years now in the software industry).

    There is such a thing as over-decomposition of a problem. When you are new to a codebase and trying to understand it though reading 60 odd 3 line functions, it can be very difficult indeed to understand the big picture.

    Its not about pesky if statements, or static vs. dynamic typing, or any other fancy buzzwords of the moment. Its about writing code that is both easy to understand and easy to maintain. And that means making decisions about what code should be in ONE place, and what code should be separated. And those decisions aren't reducible to 'lets reduce if statements', 'lets ban switches', or any other of a plethora of types types of inanities I've seen over the years.

    I for one am tired of the nonsensicle formulations that bear no resemblance to the real issues facing software development.

    Death to Idiocy (c), power to common sense!

  83. Avatar for richardjking2000
    richardjking2000 November 11th, 2013

    >>exactly<< Excellent point.

  84. Avatar for richardjking2000
    richardjking2000 November 11th, 2013

    Optimal execution is not about code execution, typically its about two other related things:

    Proper data structure design/application
    Knowing the issues with performance between:
    -Memory
    -Files on disk
    -Network I/O
    -Database I/O

    Sometimes algorithms will cause performance issues.. but I find 90% of performance issues come down to some misunderstanding of the above. How many times have I seen a linked-list implementation used when searching was important?

    Assuming the above is understood well by the programmer, writing for maintainability first is generally a good choice. There are edge cases where this isn't the case, but very few folks ever have to deal with them.. And in cases where performance becomes an issue, then code analysis is acceptable to fall back on.

    These are common sense approaches that solve 97% of the problems facing most systems..

  85. Avatar for distantcam
    distantcam November 11th, 2013

    If statements may be natural, but if logic isn't. This particular example is easily prone to an off-by-one or other mathematical errors.

    On the other hand, the LINQ operators are simple and familiar, especially if you've used them regularly. It saddens me that so many .NET developers don't use LINQ for data manipulation. LINQ has been part of the framework since .NET 3.5 so there's no excuse.

  86. Avatar for distantcam
    distantcam November 11th, 2013

    Really?! So you're in favour of highly optimized, difficult to maintain, custom frameworks rather than solving your clients problem?

  87. Avatar for Joey Guerra
    Joey Guerra November 11th, 2013

    Wow. I'm really surprised at what seems to be a mostly negative reaction to this article. I would've thought the idea of reducing code complexity by focusing on reducing conditional statements would've rung true with more people. It does with me. Here's my +1 for what it's worth.

  88. Avatar for gfdgd
    gfdgd November 12th, 2013

    Not only inelegant but it may be also erroneous.

    > There's no way I'd let such code pass review.

    Strongly agree.

  89. Avatar for Stephen Byrne
    Stephen Byrne November 12th, 2013

    I don't understand the hate on this - it's just an abstraction for a very specific requirement that saves you, the consumer of the method, from having to worry about how it works, and a simple comment on either the usage or the documentation for the method makes it clear what it does. I don't see anyone asking for the total removal of `if`....

  90. Avatar for Alex Burke
    Alex Burke November 12th, 2013

    Not at all. Ive just found that sometimes the problem becomes mine when using a library that has 'undocumented' shall we say platform bugs, or strange behaviours. Usually the client doesnt care whether its the library implementation the onus is on me to fix it.. not an easy stretch when its something you have no control over other than coming up with your own solution and probably could have done so whilst the client was paying in the main development round. Yes absolutely if something has already been done (DSP algos, FFTs, Hashing algos) then it is appropriate to us them, I wasnt implying not to. I guess its more about choice. Dont get me wrong I think the debate is worth having and yes I should always ask myself 'is it necessary what Im doing', 'is there a better way' but throwing away a screwdriver because a hammer pushes it in quicker isnt a step forwards. Its all about the balance between: yes function x is known to do this and I can implement it for £15 Id be mad to write my own vs I saved £15 but now theres a problem/bottleneck/hardware changed and shite now what do i do?. If your best guess is that the former will happen then by all means go for it, reuse what's already there. As an aside I'm assuming when throwing out the 'IF' statement we are not talking about the compiler specific ifndefs etc

  91. Avatar for truth_machine
    truth_machine November 12th, 2013

    "There's no way to understand at a glance"

    There certainly is a way: have the right skills. Functional programmers understand it at a glance.

  92. Avatar for Alex Burke
    Alex Burke November 12th, 2013

    Actually put in the manner you put it, and re-reading the article given your leaning I actually do agree and +1 on this basis.

    My initial reaction which was one biased by the examples given (and to be fair the rather incendiary title of this post) that it seemed replacing an if with what ostensibly looks like a wrapped function (which may or may not have an if in it somewhere!).

    So long as the debate is from the perspective of going through my code and seeing if there is a better way to do it, which may involve 'death to the IF statement', sometimes that's not an option (especially compiler specific ifs- C/C++) or appropriate and some of the time the 'IF' is either not needed or a ternary/binary op/switch/reversal of logic is a far more appropriate and less performance draining than a load of ill thought out if/else's.

    Sometimes the budget/sanity isnt there to nit pick through the code and sometimes you are working in a team and if/elses are a little bit easier to document (IMHO) (from experience unnecessarily jumping into a function/object to read the comments from every new line is a PITA and would get you a swift kick in the nuts from most co-workers) and if they arent in some critical part of the code what is the harm? (better doc slower code vs marginally faster code but harder to read). It still feels a little like removing a choice though...

  93. Avatar for Alejandro Varela
    Alejandro Varela November 12th, 2013

    thanks martijnhoekstra! :)

  94. Avatar for jmda
    jmda November 12th, 2013

    concur with jbblanchet. clarity is always a plus.

  95. Avatar for Bopdji Shah
    Bopdji Shah November 12th, 2013

    You forgot the DJNZ, which tells the CPU to continue doing something in a loop while a count is being decremented.

  96. Avatar for Joey Guerra
    Joey Guerra November 12th, 2013

    I agree with what your saying. I wonder if the point in the article would be better highlighted if the example presented was more like:

    if(){
    }else{
    }
    foreach(){}
    while(){}
    while(){}
    foreach(){}
    switch(){
    case:
    default:
    }

    I've totally seen code like this which had tons of control structures and branching. In that particular case, it was obvious that a tactic to reducing the complexity would be to target removing if statements and loops. I think that's why the article's point really rings true with me. But as with many things, it's good practice to strive for balance, especially when modifying existing systems, which is how I interpreted your response.

  97. Avatar for Matteo Ferrando
    Matteo Ferrando November 12th, 2013

    in Haskell:

    padded i ls = take i (ls ++ repeat 0)

    Now there is no doubt of what's happening

  98. Avatar for Anil Mujagic
    Anil Mujagic November 14th, 2013

    This "I know" part gave me a good laugh today :)

  99. Avatar for Steve
    Steve November 15th, 2013

    This is exactly the kind of bug that not using a conditional would help avoid. Your solution has 2 behaviors whereas the Concat solution only has one.

  100. Avatar for Chris Hynes
    Chris Hynes November 15th, 2013

    Not sure how you see that. Mine and the Concat solution are exactly identical semantically. Mine's just written out instead of using LINQ magic.

    And there are no conditionals in either.

  101. Avatar for puccup
    puccup November 15th, 2013

    Lack of if statements is nothing new. IBM 360 JCL didn't have if statements, neither do SNOBOL (language from the 60s), WIX Windows Installer. They have conditions, events and gotos: but no if statement as such.

    The main difference is whether you want to read the code or think about what it is doing. Lack of if statements may be elegant but it makes you think a lot more: not so good when the boss in on your back to get something out.

    If you really want to see whether you are using if statements: check the generated code. If you get any conditional branches, you have an if statement even though the code that generated it doesn't.

  102. Avatar for lazilier
    lazilier November 19th, 2013

    You're sure there are no extra entries because you Take only as many from the Concat result as you originally asked for. And you don't bother calculating exactly how many padding elements to add because 1) it's lazily done, and 2) determining the length of your source IEnumerable would mean you iterate it twice instead of once.

  103. Avatar for Guillaume Lecomte
    Guillaume Lecomte November 20th, 2013

    You evaluate the source for the .Count(), losing advantages of laziness.

  104. Avatar for Alexander Troup
    Alexander Troup November 21st, 2013

    Aside from the fact you should probably get more sleep, You've hit on what seems like the crux of the argument here:

    Some people prefer readable code over efficient, some will prefer efficient code over readable.

    That may be over simplifying though. In reality I think context is the important thing to consider in choosing here. If your code is on a hot path then you may need to have the less readable method, with the benefit of faster code.

  105. Avatar for Anonymous
    Anonymous November 27th, 2013

    Enumerable.Empty<int>().PadEnd(8).Count() // infinite loop. Why make this possible?

  106. Avatar for Rüdiger Plantiko
    Rüdiger Plantiko December 18th, 2013

    In the Ruby example, the "if" statement disappeared from the source code, but is still executed behind the scenes, as part of the "max" function.

    It is a good idea, when you are about to write an "if" statement, to look out for a more baisc function in which this particular condition is already implemented. More special and complex conditions can at least be designed as functions with Boolean return value, and chained by functional idioms like "Array.every()", "Array.some()".

  107. Avatar for Noel
    Noel January 3rd, 2014

    Phil,

    I believe there is a bug in this code based on the original problem :

    "If the number of elements I needed was larger than the number of elements in the array, I needed to pad the remaining space in the resulting array with zeros"

    So if we take the values from you example and look at the result of the "result" variable below

    var result = source.Concat(Enumerable.Repeat(default(T), count))

    we will see that the collection now has 7 elements in it!

    I know that the .Take method will still always work, however this solution does not what the problem defined.
    Maybe the if statement was the better way to go, as it solved the problem correctly

  108. Avatar for haacked
    haacked January 4th, 2014

    Huh? That's not the solution in my blog post. My blog post has this:

    ```
    return source
    .Concat(Enumerable.Repeat(default(T), count))
    .Take(count);

    ```

    Keep in mind that Enumerable.Repeat and Concat are lazily evaluated. So "result" doesn't have _any_ elements in it until you evaluate it by calling something like "ToArray" or "ToList" on it.

    That's why the "Take" is so important in my solution. That's also lazily evaluated. So when you call "ToList" on the result of my code, there is never a collection with 7 elements in it.

  109. Avatar for Scott Kensell
    Scott Kensell January 4th, 2014

    I don't see an IF statement in my python code. Long live Python and readability!

    def padded_take(array, n):
    return array[:n] + [0 for i in range(len(array),n)]

    assert(padded_take([1,2,3], 5) == [1,2,3,0,0])
    assert(padded_take([1,2,3], 2) == [1,2])
    print "Tests pass."

  110. Avatar for Noel
    Noel January 6th, 2014

    Thanks for the clarification. I was breaking it down (hence leaving out the take) and was not taking into account the lazy evaluation

  111. Avatar for RubyPanther
    RubyPanther February 16th, 2014

    As far as the Ruby goes, without the if there is no reason to even have 2 methods.

    The if is just an optimization, to avoid doing extra work if you don't need to. Seems sensible to optimize the things you know are wasteful.

    def padded_take ary, n
    ary = n <= ary.length ? ary : ary + [0]*(n-ary.length)
    ary.take n
    end


    or with a postfix if:

    def padded_take ary, n
    ary += [0]*(n-ary.length) if n > ary.length
    ary.take n
    end

    I think this is the clearest and lowest maintenance of all though.

    The #max in the example is clearly bad. Intentionally reducing performance to... de-optimize out a hated keyword. If you really want the extra method, just extract the ternary into a method. But if you think about whatever code you'd be calling it from, if the pad is safe you can just say pad(ary,n).take(n) Ideally these would be instance methods and you'd really have something like foo.pad(n).take(n) and I don't see why you'd prefer foo.padded_take(n)

    def pad ary, n
    n <= ary.length ? ary : ary + [0]*(n-ary.length)
    end
    def padded_take ary,n
    pad(ary,n).take(n) # just call this from the caller :)
    end


    (edited for code blocks)

  112. Avatar for ngo hue
    ngo hue March 17th, 2014

    thank your post. I liked so much. Please send me a little at the bottom

    Nở nụ cười sáng khoái cùng với tuyển tập truyen cuoi hay nhat vô cùng hài hước và vui
    nhộn. Bạn có hay đọc truyen cuoi vova không, cậu bé lém lỉnh này
    thường gây ra rất nhiều tình huống gây cười, hãy đọc và mỉm cười cho cuộc sống
    thêm vui nhé. Những tình huống hài hước trong tình yêu sẽ được tổng hợp trong
    truyện truyen cuoi tinh yeu, hãy đọc những truyện cười hay nhất hay nhất, mới nhất để cười
    mỗi ngày.

  113. Avatar for Edson Medina
    Edson Medina January 24th, 2016

    Ternary operations aren't much better.

    While there's no problem with:

    var foo = condition ? val1 : val2;

    It's a whole different story with:

    var foo = class.someFunction() ? class.getThing() : class.getDifferentThing();

  114. Avatar for MC
    MC July 14th, 2016

    What?! That's crazy-talk. The framework comment on IEnumerator (returned by the single method on IEnumerable obviously), states the following on the return value from MoveNext():

    Returns:
    true if the enumerator was successfully advanced to the next element; *false if the enumerator has passed the end of the collection*.

    To say it has no notion of count or finite-ness is flat out incorrect.

  115. Avatar for haacked
    haacked July 15th, 2016

    > *false if the enumerator has passed the end of the collection*

    I think his point refers to that "if" in that statement. For example, it does not say "false _WHEN_ the enumerator has passed the end of the collection".

    It says "if". There's no requirement that an IEnumerable ever terminate.

  116. Avatar for Lawrence Knowlton
    Lawrence Knowlton November 6th, 2016

    Apart from not having any training in linq and just a few courses in C#, I think that so long as the code is well documented, the code could be less 'readable'. My courses never tried to keep me from using if's and loops, I found this whole topic of their reduction highly interesting!