

No ifs...alternatives to statement branching in JavaScript - carloG
http://javascriptweblog.wordpress.com/2010/07/26/no-more-ifs-alternatives-to-statement-branching-in-javascript/

======
telemachos
Dislike of if confuses me. People claim to find conditions wordy or confusing.
I don't find conditions particularly difficult to follow, but I have a
question from the other side: when you use && and || as logic gates, don't you
(in your mind) translate them back into conditions anyhow? Here's his first
example without if:

    
    
        function getEventTarget(evt) {
            evt = evt || window.event;
            return evt && (evt.target || evt.srcElement);
        }
    

Sure, it's very short in this written form. But for me to _understand_ it, I
need to think, roughly: evt retains its value, if it's a truthy value;
otherwise give evt the value of window.event; if evt is a true value (now),
return it and the value of evt.target - if that's truthy, or, if not, add in
the value of evt.srcElement; oh, and by the way, if evt was not truthy
initially in the return statement, bail out early (and return no value) since
&& only continues on if the initial value is true.

I'm not trying to be difficult, but I don't see that as miraculously _more_
clear.

~~~
geuis
Look at it like this. I am a developer who prefers the terse code compared to
the longer if() variety. I've been doing this long enough that its is easier,
clearer, and faster for me to understand the "evt = evt || window.event" than
it is to trace through all of those if() statements.

I used to be the opposite, I couldn't understand the short form or how it
worked. Ternaries confused the hell out of me for a while. Why?

Because when I look at "evt = evt || window.event", my mind has learned about
the conditionals that each of these represent. Its analogous to phrases that
mean different things in different contexts. "That guy has balls", for
example.

So I look at it and I know that "if( evt )" is the same as "evt ? true:false"
as "if( typeof evt !== 'undefined' ). I know that in the context of that
statement, evt || window.event is saying "if evt exists, use that. if not, use
window.event".

So the reason its confusing to people is they haven't learned all of the
different things the shorter code means.

For me, after having spent many, many hours writing javascript I find the
short form easier to understand and less tiring. Not only that, in raw numbers
it just saves space.

Now, the other lesson I've learned over the years is that many times it is
much better to start out writing in plain old "if" statements. Get the logic
right, then reduce it down. There's nothing more annoying than trying to debug
someone else's poorly written code.

And for god's sake, DOCUMENT!

~~~
wmwong
I agree that in some cases, guards, defaults and ternaries flow more
naturally. However, I feel that there's a contradiction. You say that it is
easier to understand but have learned to write them in plain old "if" first
because it's better. It's easier to get it wrong if you write it shorthand. If
it's better to start writing them in "if", doesn't that mean it's easier to
understand? If it is easier to use guards, defaults, and ternaries, you
shouldn't have to resort to plain "if" to get the logic right. And I agree,
DOCUMENT!

~~~
scott_s
We sometimes use if-else statements to write out some straight-up logic
because we don't _understand it_ at first. So we build it from the ground up.
If, after writing it all out with primitives, we realize "Oh, it's just this
anded with this and ored with that" then we actually _understand_ the problem.

Put another way: if you write a boolean expression as a sequence of
statements, my assumption is you don't really understand what you're doing.

------
jasonkester
"That's very clever."

The above quote comes from the smartest developer I've ever known, talking
about a piece of code I had written that I was just as proud of as this guy is
of his ifless branching. It took a minute to sink in that "clever" is not a
term you want people using to describe your code.

As a developer, the first time you're going to encounter any piece of code is
when FireBug drops you into it with an exception. Personally, I'd prefer to
look at a single line that does a single thing.

For any non-trivial implementation of the author's chained implicit
conditional logic, a null reference exception will leave you looking at a
single line with a half dozen candidates for what might actually be throwing.

Please please please don't make a habit of coding like this for anything but
the most trivial cases.

------
angusC
Hi - I 'm the author of this post. A few comments:

1) It wasn't my intention to create a holy war. There are good arguments on
both sides. I use ifs and fors in my own code and will continue to do so.

2) Over the years I have developed a distaste for the _overuse_ of statement
branching - I find it distracting and I feel it works against readability.

3) I wanted to catalog a bunch of (mostly well known) alternatives to present
as a coding strategy

4) I realize that not everyone likes such terseness of style and what is clear
syntax to one person can be undecipherable to the next.

5) Use what ever works best for you and your team

(Notice how procedural this comment was :-) )

------
aufreak3
From the title, I was expecting something interesting like "SubText", or at
least some kind of talk about dispatch :) Using &&, || etc gets you terse
code, but the branching that you mentally work out is exactly the same.

.. unless you use the && and || _so much_ that you end up chunking out
specific patterns of usage without having to explicitly think about the
branching.

.. which you _can_ do with if as well.

------
kwamenum86
Write readable code for your source files and then compile with Google's
closure compiler.

------
BoppreH
I'm a very young coder and loved the article, especially how it brings
functional features to imperative languages.

But what if I write the entire company framework without a single conditional
(including loops)? Are this alternatives to be used sparingly or as much as
possible? Would you frown upon when you see it?

On a side note, I would love to never see a conditional again Even before
learning functional programming I felt bad at every "if" and especially every
"for" loop, but now I know why.

~~~
mrj
What if you did? Would it be a better framework? Would anybody care at all?

I doubt it.

This a code style and if you like it, then maybe you use the parts you want.
But "micro branching" is still branching and it makes little difference how
you do it (except the nod to performance concerns towards the end).

Thinking about code style and readability is useful and good, but this is by
no means a common way to code. Beware of excess cleverness. It would be far
better to worry about the correctness of the code rather than optimizing for a
meaningless benchmark (no ifs).

~~~
BoppreH
It would not be for cleverness, much less for optimization (is it even
faster?)

For some reason every time I see a condition I cringe mentally. There's
something in a "for" loop that makes me uncomfortable and god, using "map",
"filter" and micro branching would help a lot.

I'm just thinking of what I would like to see and checking it against the
opinion of others.

~~~
mrj
Maybe it's a coding style that suits you then. That's cool.

I just caution against putting it in such simple terms. I hate it when I read
code by somebody who latched on to the latest trend and then ruthlessly bent
their style to match the new way, whether it made sense or not.

As for performance, it would have to be tested. In some languages with first-
class closures, a lot of code like the examples might seriously strain the
garbage collector (if present). There might be a ton of young objects to clean
up, all the time. That was my only thought on it.

------
forinti
A collection of ifless techniques for those of you lucky enough to read
portuguese:

<http://alquerubim.blogspot.com/search/label/ifless>

------
planckscnst
Doesn't this depend on strict lazy evaluation? I could imagine if the
implementation underneath changed (possibly to take advantage of parallel
execution), if any segment had side effects, it would be horrible.

~~~
lygaret
I can't think of a case where lazy evaluation would be required, only that the
semantics of the && and || operators not change.

It's defined as part of the language that && will not evaluate the right hand
side unless the left hand side is truthy. A lot more than using this stuff as
branching would break if some implementation arbitrarily decided to not follow
that anymore.

~~~
thienan
Thanks

------
fortes
One of the things I love about Google's Closure Compiler is that it takes care
of these optimizations for you. If you want, you can write in an explicit
readable style and still get any performance benefits.

~~~
alexfarran
But these are not performance optimisations.

Angus is making the case that functional techniques can be more concise and
readable than procedural style control flow.

~~~
_delirium
Are short-circuiting boolean operators as conditional-plus-result-rolled-
together really a _functional_ technique? Certainly in strongly typed
functional languages like Haskell they're impossible, because his example
isn't even well-typed:

    
    
      evt && (evt.target || evt.srcElement)
    

You can't apply a boolean operator to an event! And even if you could, the
result would always be a boolean. I associate this most commonly with
languages I wouldn't really call functional, like Perl and Ruby (I believe
Perl popularized the technique).

Even in Lisp, where you can write like that, it's much more idiomatic to use
the _if_ or _cond_ forms, which is more morally equivalent to C's ternary
conditional than to short-circuiting booleans.

~~~
JadeNB
> evt && (evt.target || evt.srcElement)

It's certainly true that this isn't well typed (not to mention not valid
Haskell, since the . is used for namespacing, not access to member variables),
but there's no reason that one couldn't do something conceptually similar:

    
    
        class Boolable a where
            toBool :: a -> Bool
            (&&)   :: a -> a -> a
            (||)   :: a -> a -> a
    
            a && b = if (toBool a) then b else a
            a || b = if (toBool a) then a else b
    
        instance Boolable Int where
            toBool 0 = False
            toBool _ = True
    

I don't know how idiomatic this is, but it works. One can see that it really
is short-circuiting:

    
    
        > :l Boolable
        [1 of 1] Compiling Main             ( Boolable.hs, interpreted )
        Ok, modules loaded: Main.
        > 1 Main.|| undefined :: Int
        1
        > 1 Main.&& undefined :: Int
        *** Exception: Prelude.undefined
    

I don't know Haskell well enough to know why the `:: Int` on the end is
needed, but I'm sure that that, too, can be worked around.

------
konad
Eventually you will learn to stop doing this.

