22

In Groovy, there is a nice syntax for working with null values.

For example, I can do an if statement:

if (obj1?.obj2?.value) {

}

This will not throw a NullPointerException even if obj1 is null (it will evaluate to false).

This is something that's very convenient, so wondering if there is a Ruby equivalent I missed.

Yu Hao
  • 115,525
  • 42
  • 225
  • 281
Jean Barmash
  • 4,758
  • 1
  • 31
  • 40
  • 2
    http://stackoverflow.com/questions/8805582/is-there-an-equivalent-null-prevention-on-chained-attributes-of-groovy-in-ruby – tim_yates Jun 22 '12 at 21:02
  • thanks! Also found the andand gem just now that tries to introduce this to ruby through a method: http://weblog.raganwald.com/2008/01/objectandand-objectme-in-ruby.html – Jean Barmash Jun 22 '12 at 21:04
  • Not yet in a stable release, but the development branch of Ruby now has the `.?` operator. See https://bugs.ruby-lang.org/issues/11537?utm_source=rubyweekly&utm_medium=email#note-12 – Ryan Sandridge Oct 23 '15 at 18:16

4 Answers4

24

In a rails app there is Object#try

So you can do

obj1.try(:obj2).try(:value)

or with a block (as said on comments bellow)

obj.try {|obj| obj.value}

UPDATE

In ruby 2.3 there is operator for this:

obj&.value&.foo

Which is the same as obj && obj.value && obj.value.foo

Ismael
  • 16,110
  • 6
  • 57
  • 74
  • 3
    Or alternately: `obj.try {|obj| obj.value}` - block mode often makes more visual sense IMHO. – Irongaze.com Jun 24 '12 at 02:49
  • This block syntax makes the most sense when you want to do something with the value like call a method on it. – Josh Diehl Oct 20 '13 at 16:13
  • A common pattern to tackle this kind of problem are [null objects](http://robots.thoughtbot.com/post/20907555103/rails-refactoring-example-introduce-null-object). – Patrick Oscity Oct 21 '13 at 10:36
  • 2
    Note that [`Object#try`](http://api.rubyonrails.org/classes/Object.html#method-i-try) is a part of the [ActiveSupport](https://github.com/rails/rails/tree/master/activesupport) gem, which can also be used outside of Rails. – Nick McCurdy Jun 09 '14 at 21:28
  • 1
    *"Which is the same as"*... This is not true when `obj` is `false`. – user513951 Jan 04 '16 at 22:48
  • Thanks Jesse for the heads up – Ismael Jan 04 '16 at 23:56
  • @Ismael I see this equivalency stated in every resource I can find about the new operator. I posted a new question regarding this misinformation: http://stackoverflow.com/questions/34602054/what-is-the-closest-equivalent-to-rubys-safe-navigation-operator – user513951 Jan 05 '16 at 00:00
  • `[20] pry(main)> @asd.try(:asd) NoMethodError: undefined method `try' for nil:NilClass` – akostadinov Mar 08 '16 at 15:39
  • @akostadinov try is only available with ActiveSupport (part of Ruby on Rails) – Ismael Mar 08 '16 at 16:20
6

This has been added to Ruby 2.3.

The syntax is obj1&.meth1&.meth2.

jeremywoertink
  • 2,143
  • 1
  • 22
  • 28
3

Ruby 2.3 will have support for the safe navigation operator:

obj1&.obj2&.value

https://www.ruby-lang.org/en/news/2015/11/11/ruby-2-3-0-preview1-released/

Mario Pérez Alarcón
  • 3,100
  • 2
  • 24
  • 36
2

try was the only standard way to do this before Ruby 2.3. With Ruby 2.3 you can do:

if obj1&.obj2&.value

end

Also, if you have a hash structure, you can use the _. operator with Hashie:

require 'hashie'
myhash = Hashie::Mash.new({foo: {bar: "blah" }})

myhash.foo.bar
=> "blah"    

myhash.foo?
=> true

# use "underscore dot" for multi-level testing
myhash.foo_.bar?
=> true
myhash.foo_.huh_.what?
=> false
jeremywoertink
  • 2,143
  • 1
  • 22
  • 28
Javid Jamae
  • 8,383
  • 4
  • 44
  • 61
  • So, try *was* the only way to do this when I answered the quesiton. The &. notation was just added with Ruby 2.3. The downvote wasn't really necessary, a comment or edit would have been appreciated. – Javid Jamae Jan 08 '16 at 06:15
  • Not sure if your downvote was related, but I just made an edit because you were using JavaScript syntax for your if statement. – jeremywoertink Mar 10 '16 at 17:24