Recently the Groovy team introduced a new operator to the Groovy language. It is called the Elvis operator. There is one thing I particularly like about this operator. It's name.

To bad the Elvis operator is only a shortening of Java's ternary operator, written like ?:. One use-case for the operator is returning a 'sensible default' value if an expression resolves to false or null. A simple example might look like this:

GROOVY:
  1. groovy:000> name = null
  2. groovy:000> displayName = name ?: "anonymous"
  3. ===> anonymous

I had a good laugh about it with some people at JavaPolis, and forgot about it. Until I noticed something while reading the expressions chapter in the PickAxe (I'm trying to boost my Ruby knowledge).

In Ruby anything which isn't nil is true in an expression. Due to this behavior the result of a shortcut expression doesn't have to be a boolean but is actually the value which evaluated to true (in Groovy the result is a boolean). This means Ruby implicitly has a 'Elvis' operator.

RUBY:
  1. irb(main):069:0> name = nil
  2. irb(main):070:0> displayName = name || "anonymous"
  3. => "anonymous"

Even better, Ruby allows you to use the shortcut OR in combination with the assignment operator:

RUBY:
  1. irb(main):072:0> name = nil
  2. irb(main):073:0> name ||= "anonymous"
  3. => "anonymous"
  4. irb(main):074:0> name = "peter"
  5. irb(main):075:0> name ||= "anonymous"
  6. => "peter"

Funny to see how a slightly different behavior of something like to or operator makes it even more useful!


5 Responses to “How Elvis showed me a neat way of using operators in Ruby”

  1. 1 railsguru

    It's very useful to init a variable which might have been initted before, at least that's where I use it most frequently e.g.:

    queue ||= []

    // now you're sure you have a valid queue array

  2. 2 mich.barsinai

    I'm afraid that is just another case where ruby tries to be nice and then stabs you in the back unintentionally. There is a very good reason for groovy to go with "?:", and that is values inited to false.

    display_icons ||= true
    would *always* set display_icons to true, even if it was inited to false.

    Suppose you have a rails application. And suppose that you have a partial which you render with a bunch of locals. One of them might be "display_icons", which you want to be true unless otherwise defined. You put the above snippet at the top of the code (real gurus would probably iterate on the keys and of the hash to do that, and would get bitten much harder). You then render the partial with :locals=>{:display_icons=false}, and you would still get the icons.

    Operator overloading is trickier than one might think. There's a reason why it's not in java (see also here: http://cafe.elharo.com/java/operator-overloading/).

    BTW, if ?: called Elvis (why?), I propose we call the ruby || operator "Wham!" (it does look like 2 skinny guys, and it is the sound your forehead would make when hitting the keyboard after you realized why those icons were showing all the time :-).

  3. 3 peter

    Thanks Mich, this is a very valid point. The Elvis operator 'suffers' from the same problem:

    groovy:000> a = false
    ===> false
    groovy:000> c = a ?: true
    ===> true
    

    And yeah, I like the "Wham!" concept!

  4. 4 levi_h

    >> display_icons ||= true
    >> would *always* set display_icons to true, even if it was inited to false.

    But that's what you'd expect, right? That the || (or 'or') operator would return true for true and false? And with that in mind, you'd more likely write something like display_icons = (display_icons.nil? ? true : display_icons).

    As I understand it, C# has the same operator, ??, that returns a default value if the lhs is null. It would be nice to have an operator like this in Java as well: it especially pays off with longer expressions, which almost require you to introduce a local variable.

  5. 5 peter

    @levi yes, those results are as expected... it's Rubys' way of avoiding having booleans with three states.

    Your fix works, but personally I would avoid using the ternary operator in Ruby to solve this... I'd use a trailing if solution:

    display_icons = true if display_icons.nil?
    

    By the way, since autoboxing was added to Java this is sort of a problem:

    Boolean b = null;
    
    if(b){
      System.out.println(b)
    }
    

    This throws a NullPointerException during unboxing; whereas Ruby or Groovy evaluate the expression correctly (assuming that the uninitialized state of a boolean is false).

Leave a Reply





About

Welcome to the weblog of Peter Maas. Here you'll find various posts related to stuff I like (like my kids and espresso) and stuff I do (like developing software).

JavaOne 2008 Pictures


Stage being build in the nearby park Rudie Joshua Bloch at JavaOne2008 Okke en Rudie javaone 2008 goodybag Java + You on a cab Cable Car line Acme Anvile at CommunityOne Keynote Moscone Center - JavaOne Hotel room sea_lion Charles Nutter & Guillaume Laforge pub golden_gate_warning_sign alcatraz smashmouth Stretched Limo nearby hotel Community One Keynote Scribbled Sun Logo
View more photos >

Categories



Meld u aan voor PayPal en begin direct met het accepteren van creditcardbetalingen.