Assignment inside a Condition

Tweet

It’s very common in PHP to see code written like this:

if($summary = get_post_summary())
{
    return $summary;
}

What I’m referring to is assignment inside a condition. Cunningly enough, it can be done in JavaScript too, although it’s far less common:

if(summary = document.getElementById("post-summary"))
{
    return summary.innerHTML;
}

At first glance you’d be forgiven for thinking that’s a typo! Indeed, some debuggers will flag that with a warning, asking if you meant a test for equality (==) and mistyped it as assignment (=).

But it’s not a mistake—the key to understanding it is to understand two things:

First, assignment returns a value (the value you assigned). Second and most importantly, the value it returns evaluates to true or false, and ultimately determines whether the condition passes.

Now, in the world of DOM evaluation and traversal, this technique is a safe and predictable one because DOM nodes either exist or they’re null—and null is required to evaluate to false. So in the code example above, the condition will evaluate to true if the "#post-summary" element exists, or false if it doesn’t.

Equally, you can use the same trick to iterate up an unknown hierarchy, traversing through successive parents using while(). This example builds an array of every node name between an event target and the #document:

var names = [], node = e ? e.target : event.srcElement;
do
{
    names.push(node.nodeName);
}
while(node = node.parentNode)

But elsewhere in JavaScript, you could find yourself in much less reliable territory, because how true or how false many values turn out to be is not at all intuitive.

Both positive and negative numbers, for example, evaluate to true except zero and NaN. And bizarrely, an object created with the Boolean constructor always evaluates to true, even if it was created as new Boolean(false)!

So be warned! Syntax like this is not for the fainthearted; nor should it be used in a cavalier way, with overreliance on type conversion and the casting of arbitrary values. But used well in suitable circumstances, it can simplify many conditions to produce faster and leaner code.

Thumbnail credit: sbwoodside

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • tbela99

    I do it regularly in php, but oddly I consider it as a bad pratice when it comes to javascript, I always consider it as a typo. it is very hard to debug this kind of errors

  • Paul McKeown

    Simply a bug magnet in Javascript. Don’t do it.

  • Anonymous

    interesting.. thanks for the article

  • mech7

    If you want to return it why assign a new var? I don’t see the point

  • http://preachers-kid.com Jerrac

    Interesting tip, but I personally find it not worth the extra speed. It’s odd syntax that takes more time to figure out than I find it’s worth. Especially if you are new to the code and it isn’t commented/documented well.

  • Simon

    I agree wholeheartedly with the first two posts. There’s a big difference between things you CAN do in a programming language and things you SHOULD do and experience shows that this technique should be avoided.

    The aim today is to write code that is reliable and bug-free rather than clever. Current best practice is to separate code into lines that do one thing very explicitly (so both logical and syntactical bugs are easier to spot sooner) and to specificly avoid this sort of composite statement.

  • phrenetical

    I’ve used this technique in performant and byte critical apps before, it saves you the trouble of two separate dom lookups to determine if a node exists, and can eliminate an extra variable assignment.

    // Two lookups
    if($(‘someNode’)) {
    return $(‘someNode’);
    }

    // Var assignment
    var tmpNode = $(‘someNode’);
    if(tmpNode) {
    return tmpNode;
    }

    // Performant
    if(tmpNode = $(‘someNode’)) {
    return tmpNode;
    }

    Depends what your doing as to whether it is useful or not, just highlighting why and how I’ve used it before.

  • KenD

    The usage is fine, as long as you have the courtesy to add a comment. “This is not a bug. It is an assignment with a boolean result.” In your own words.

  • skylark

    I usually do PHP where it’s commonplace but once tried it in JS and it didn’t work – now I realise it probs wasn’t a DOM operation. Thanks for the clarification.

  • Anonymous

    Paul is right. Its a bug magnet.
    There is nothing you can do with assigning in a condition that you can’t do in much more readable code.

  • Keith Thompson

    This method definitely creates the room for ambiguous condition statements and in turn room for buggy code. We use a slightly different syntax for this type of assignment in both PHP and JavaScript:
    if ( ($summary = get_post_summary()) == true )
    {
    return $summary;
    }
    AND
    if( (summary = document.getElementById(“post-summary”)) == true )
    {
    return summary.innerHTML;
    }
    The beauty of this method is that you can test any value

    • http://www.yacare.fr McBenny

      I think this method is a bit redundant.
      The if statement is evaluated to true or false, so comparing a value or an assignation to true is doing the job two times, isn’t it ?

  • http://lukemorton.co.uk Luke Morton

    I thought it’s best in all programming languages not to use it. It tends to decrease the readability of the code. Programmatically it’s interesting to know how it works, but there is no real need to ever do it.

  • http://www.tonymarston.net Tony Marston

    Personally I think that it’s a bug in the compiler if can’t determine that an ‘=’ inside a condition is a test whereas an ‘=’ outside of a condition is an assignment. Surely the compiler should have enough intelligence to know whether it’s inside a condition or not? It’s not rocket science, is it?

    • skylark

      @ Tony Marsden, it’s not a ‘bug’…
      The ‘=’ in a construction like “if ($var = funccall()){…}” isn’t a test or comparison, it’s a variable assignment … the function is called and the result assigned to $var. The expression “$var = funccall()” is evaluated by the “if” as Boolean true or false: *that* is the test.

  • ringobob

    @Tony

    It’s not a bug precisely because this type of behavior was intended. At least, it is in PHP, where this kind of assignment is used commonly specifically for iterating functions, such as reading successive lines from a file in a while loop. There are a few such cases where it makes syntactic sense and is a common convention (if you see this function assignment in the conditional, you know it’s intentional).

    I’m not sure the same condition exists in javascript, though I’ll admit the example code in the article testing for existence of a DOM object is attractive to me. I’d probably just use 2 DOM lookups rather than the assignment, but if I had particular reason to do the assignment, it actually looks far more readable to me to put that assignment in the conditional… that way I immediately know that the assigned variable is essentially scoped to that block. I don’t have to look elsewhere for it, and if it shows up somewhere else then I can be pretty sure that’s an error.

    It seems much more straightforward to put a note saying the assignment is intentional than to put a note saying that the variable is only going to be used for the conditional block (when, absent the syntactic enforcement, that could far more easily change).

  • http://www.tonymarston.net Tony Marston

    You say that it’s not a bug because it allows you to write clever code like “if ($var = funccall()){…}”, but I’m not a fan of such clever code if it has the potential for nasty side effects. I do not like the idea of cramming as many instructions as possible into a single line with the notion that it is “more efficient”. To me the readablity of code is more important as it makes the code more maintainable. The fact that a simple statement such as “if ($var = ‘foo’)){…}” does not work as intended pisses me off more than having the ability to write clever code.

    Besides, when I look at code such as “if ($var = funccall()){…}” I have to examine it very closely to see exactly what it means. Is it assigning the value of funccall() to $var and then testing the result as being either TRUE or FALSE? Or is it testing that the result of funccall() is the same as the contents of $var? Depending on the language it could be either, and I’d rather not waste my valuable time in trying to find the answer because the original coder was too lazy to write 2 lines of code instead one.

    This type of construct breaks the KISS principle, so I don’t like it one little bit.

  • http://www.brothercake.com/ James Edwards

    “Don’t use a construct because it might be confusing to read”..? To me, that’s a very odd point of view — it’s like saying “don’t do anything too hard”.

    Have you had a look at some of the code jQuery uses? Or base2? There’s code in there so complex and subtle that I don’t even understand the terminology, let alone the functionality. The simple fact is, the guys who wrote those two libraries are more knowledgeable programmers than I am — should I frown on their coding-style because it intimidates me?

    I mean if it really does bother you, don’t use it. But otherwise, it’s faster and uses less memory than a separate assignment and condition; I’d venture to say, it’s simpler too. But as I said, it’s not always appropriate, and yes, it’s potentially confusing.

    So a comment might not be a bad idea if others are expected to work with the same code-base.

  • Ryan Beard

    Personally I quite like clever optimisation techniques like this. I agree with @phrenetical – in some situations it’s a nice shorthand to avoid an extra function call or a separate variable assignment. On the down-side, most of the time you’ll want to define your variable within the scope of the function e.g:

    var myVar;

    …but the var keyword is invalid syntax within an if statement, for example:

    if (var myVar = document.getElementById(“some-element”)) {
    alert(myVar.id);
    }

    …would break. But if you’ve already defined your local variable, this won’t be a problem. It all depends on whether you’re coding for yourself or on a shared project. If you make people aware this is a technique you’ll be using, I don’t see any harm.