23

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
  • 119,891
  • 44
  • 235
  • 294
Jean Barmash
  • 4,788
  • 1
  • 32
  • 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 Oct 23 '15 at 18:16

4 Answers4

25

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 Abreu
  • 16,443
  • 6
  • 61
  • 75
  • 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 Abreu 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 Abreu Mar 08 '16 at 16:20
7

This has been added to Ruby 2.3.

The syntax is obj1&.meth1&.meth2.

Patrick Brinich-Langlois
  • 1,381
  • 1
  • 15
  • 29
jeremywoertink
  • 2,281
  • 1
  • 23
  • 29
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,281
  • 1
  • 23
  • 29
Javid Jamae
  • 8,741
  • 4
  • 47
  • 62
  • 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
2

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,468
  • 2
  • 27
  • 38