rubyreturn

Why is there no "returnif <expr>" that could replace (and optimize) the pattern "return <expr> if <expr>"


I often find myself typing this pattern for a variety of reasons:

return <expr> if <expr>

Not only does this seem wasteful, but if <expr> has any sort of evaluation time, then it makes more sense to do this:

tmpVar = <expr>
return tmpVar if tmpVar

But it seems silly to have to make a tmpVar just do this, and it's even less readable. I've always wanted something like this:

returnif <expr>

That returns the expression if it ends up evaluating to a non-nil/false value.

Unfortunately this isn't something that can be easily added to the language from inside of the language because it alters control flow.

Is this that unusual of a request or perhaps that unusual of a pattern for most people? I'm surprised that neither ruby nor perl seems to have a construct like this yet.

And for extra credit - are there any languages that have this kind of a construct?


Solution

  • Unfortunately this isn't something that can be easily added to the language from inside of the language because it alters control flow.

    This particular control flow can be done from blocks in Ruby, though:

    def guard(x)
      yield x if x
    end
    
    guard(expensive.operation) { return _1 }
    # or `return it` in 3.4+
    

    Is this that unusual of a request or perhaps that unusual of a pattern for most people? I'm surprised that neither ruby nor perl seems to have a construct like this yet.

    And for extra credit - are there any languages that have this kind of a construct?

    Many languages have the potential for some kind of similar guard pattern, although it usually involves a variable. That’s because what you’re asking for just isn’t that common as a need, especially compared to the opposite (returning nil when a value is nil – see try/? operators). They include…

    Rust

    if let Some(x) = expensive_operation() {
        return x;
    }
    

    or functionally,

    expensive_operation().or_else(continuation)
    

    Go

    if x := expensiveOperation(); x != nil {
        return x
    }
    

    Swift

    if let x = expensiveOperation() {
        return x
    }
    

    Haskell

    import Control.Applicative (Alternative (..))
    
    expensive_operation <|> continuation
    

    (and probably some do-notation option I’m not aware of)

    Python

    if (x := expensive_operation()):
        return x
    

    C#

    if (ExpensiveOperation() is Foo x) {
        return x;
    }
    

    JavaScript

    expensiveOperation() ?? continuation()
    // or || for falsy values
    

    I can keep expanding this, but you get the point.