News for hackers. Stuff that matters.
Re:Avoid Else, Return Early (2013) by Cthulhu_ on Monday March 26, 2018 @08:24AM (#16678284)
A more formal name for this approach is / could be Guard Clauses: https://refactoring.com/catalog/replaceNestedConditionalWith.... This pattern has been elevated to a language construct in Swift: https://thatthinginswift.com/guard-statement-swift/
Re:Avoid Else, Return Early (2013) by toomanybeersies on Monday March 26, 2018 @08:49AM (#16678422)
I was more or less required to use guard clauses by my manager at my previous job.

I used to hate being forced to use them, just because as a recent computer science graduate I was happy with nested conditionals everywhere. But guard clauses make life so much easier, I eventually discovered.

They make testing your code a lot easier, and also make reasoning about the code and reading it so much easier.

Ruby makes writing methods with guard clauses a breeze, since you can just write something like `return if x > 7`.

Re:Avoid Else, Return Early (2013) by rimliu on Monday March 26, 2018 @11:18AM (#16679521)
guard also lets you unwrap your optionals and have them in scope for the rest of the function.
Re:Avoid Else, Return Early (2013) by gwbas1c on Monday March 26, 2018 @01:21PM (#16680622)
It makes logging easier
Re:Avoid Else, Return Early (2013) by davidkuhta on Monday March 26, 2018 @09:21AM (#16678630)
Agreed, when I was first exposed to Guard clauses, (albeit in Elixir), I was amazed at how intuitive it felt to use them.

https://hexdocs.pm/elixir/master/guards.html

Re:Avoid Else, Return Early (2013) by philipodonnell on Monday March 26, 2018 @11:48AM (#16679741)
As usual I found myself writing these more and more before finding out there was a word for them.

Are there any preprocessors or libraries to make statements like this easier in Javascript? Sometimes the guard statements can be longer than the function code and I go back and forth on whether to throw (forces the caller to anticipate) or return (causes lots of silent failures).

It would be great to use a defined approach.

Re:Avoid Else, Return Early (2013) by amyjess on Monday March 26, 2018 @11:17AM (#16679510)
Yes, I love guard clauses!

I work in Python, and one thing I do if I end up needing to use the same guard clause in several functions is to turn it into a decorator. That way, if I need to update the logic, I can do it in one place and have it propagate everywhere and it makes the function's dependencies clear at first glance.

This was my introduction to aspect-oriented programming, which I've thoroughly fallen in love with.

Re:Avoid Else, Return Early (2013) by Waterluvian on Monday March 26, 2018 @08:49AM (#16678426)
JavaScript has the guard operator. It can really clean up your control flow when you know it's a guard operator and not just logical AND.
Re:Avoid Else, Return Early (2013) by timoxley on Monday March 26, 2018 @09:07AM (#16678538)
A big gotcha with `&&` as a guard in JS is that it can return any falsey typed value if you don't coerce the guard to a boolean.

e.g.

    const check(cond) => cond && otherValue
If `cond` is falsey, it returns `cond`.

This means the function could return any of: `false`, `undefined`, `null`, '', `0` or `NaN`.

This is a fairly common issue I see with React + JSX:

    <div>{cond && <SomeComponent />}</div>
If `cond` is `false`, `null`, `undefined` or '', everything will be just fine, but if `cond` happens to be a zero or `NaN`, suddenly you have a weird `0` or `NaN` rendering in your page. Oops.

Low cost, much safer guard:

    const check(cond) => !!cond && otherValue
Re:Avoid Else, Return Early (2013) by sergeykish on Monday March 26, 2018 @04:51PM (#16682469)
Quite interesting. For a moment I've thought it is another JS issue but no. It's React who's strange https://github.com/facebook/react/blob/v0.11.2/src/browser/u... https://github.com/facebook/react/blob/v0.11.2/src/utils/tra...

Same behavior on Ruby:

    def content_markup(children)
      case children
      when String, Numeric
        children
      when NilClass, TrueClass, FalseClass
        return
      else
        # ...
      end
    end

    content_markup 'foo'
    #=> "foo"
    content_markup 0
    #=> 0
    content_markup true
    #=> nil
    content_markup false
    #=> nil
    content_markup nil
    #=> nil
Re:Avoid Else, Return Early (2013) by Waterluvian on Monday March 26, 2018 @09:42AM (#16678758)
Good point. Good example. I imagine it works well in my cases but I haven't come across cases like your example where it breaks down.
Re:Avoid Else, Return Early (2013) by acjohnson55 on Monday March 26, 2018 @10:55AM (#16679343)
...until you do.

That's the problem with antipatterns. It's impossible to remain alert to the edge cases, and then they eventually bite you in production. Better to lint them away. But it's difficult to convince people not to do something really convenient if they haven't gotten bitten yet.

Re:Avoid Else, Return Early (2013) by sgustard on Monday March 26, 2018 @11:14AM (#16679488)
Yes, back when CoffeeScript was in vogue the ? operator handled this case nicely:

  cond? && otherValue
Re:Avoid Else, Return Early (2013) by arghwhat on Monday March 26, 2018 @09:14AM (#16678589)
Logical AND in JavaScript can be used as a guard, by why in the world would you think of it as anything other than a logical AND?

If you start thinking it is a "guard operator", I would think that going down the wrong path, which might promote misunderstanding of the behavior.

Re:Avoid Else, Return Early (2013) by timoxley on Monday March 26, 2018 @01:22PM (#16680639)
> which might promote misunderstanding of the behavior

This isn't a misunderstanding, binary logical operators in JS short-circuit like this by design. I believe && and || returned a boolean value in the past, but were explicitly changed to support this behaviour.

Re:Avoid Else, Return Early (2013) by arghwhat on Tuesday March 27, 2018 @04:37AM (#16686464)
Quoting ECMA-262 First Edition (June 1997), Chapter 11, Section 11 (Binary logical operators)[1]:

    The production LogicalANDExpression : LogicalANDExpression && BitwiseORExpression is evaluated as follows:
    
    1. Evaluate LogicalANDExpression. 
    2. Call GetValue(Result(1)).
    3. Call ToBoolean(Result(2)).
    4. If Result(3) is false, return Result(2).
    5. Evaluate BitwiseORExpression.
    6. Call GetValue((Result(5)).
    7. Return Result(6).
That is, the behavior has always been "If the first expression is false-ish, return the first expression, otherwise return the second expression" ("BitwiseORExpression" is a class of expressions that include a lot of things, including equality operators).

JavaScript does not have any operators that is not explicitly listed in a version of ECMA-262. It would be correct to refer to the construct as a "guard", but incorrect to refer to it as a "guard operator". Calling it "guard operator" also does not promote an understanding of the underlying construct.

1: https://www.ecma-international.org/publications/files/ECMA-S...

Re:Avoid Else, Return Early (2013) by timoxley on Tuesday March 27, 2018 @09:43PM (#16694487)
> the behavior has always been

The ECMA spec only defines Javascript 1.3 and above. See this description for logical operators for Javascript 1.1: https://web.archive.org/web/20060318153542/wp.netscape.com/e...

Re:Avoid Else, Return Early (2013) by arghwhat on Thursday March 29, 2018 @07:45AM (#16706189)
ECMA-262 defines ECMAScript. "JavaScript 1.3" refers to a Netscape-specific language implementation ("Mocha", "LiveScript", "JavaScript"), with version 1.3 being based partially based on ECMA-262 Second Edition. Some of it might still live on in Firefox, but it is certainly not what people refer to as "JavaScript".

Doing some research, it appears that Netscape changed the logical operator behavior in version 1.2 (https://web.archive.org/web/19981202065738if_/http://develop...).

However, they did not highlight this change at all (https://web.archive.org/web/19970630092641fw_/http://develop...), so I suspect it was just a minor cleanup, potentially related to the equality operator change.

As a side-note: Netscape scripting was awful. This was how you casted an object to a Number:

    Number(x) = x;
Re:Avoid Else, Return Early (2013) by romwell on Monday March 26, 2018 @04:53PM (#16682495)
And a good name for the bad style is Arrow Anti-Pattern[1]

This article also discusses the solutions (there's a lot of overlap with OP's article).

http://wiki.c2.com/?ArrowAntiPattern

Re:Avoid Else, Return Early (2013) by flanbiscuit on Monday March 26, 2018 @09:59AM (#16678907)
I learned some Swift when it as at 1.2 and I'm happy to see it evolve so quickly and take common statements, like the optional unwrapping "very long `if let` statement" mentioned article, and simplify it. I really should get back into Swift.
Re:Avoid Else, Return Early (2013) by yoz-y on Monday March 26, 2018 @10:10AM (#16678999)
Swift also has the `defer` statement which makes this particular approach usable even if there is cleanup to do before the function can exit.