Emulating a Groovy feature?

Guys,

There’s something called Safe Navigation in Groovy
(http://groovy.codehaus.org/Statements#Statements-Safenavigation) that I
find very appealing.

So, Groovy will allow you to safely walk an object graph, even if that
graph has nulls in it (the walk will short circuit):

def foo = null
def bar = foo?.something?.myMethod()
assert bar == null

Is there an easy way to hack an equivalent out in Ruby?

Thanks,
John

on) that I find very appealing.
Thanks,
John

Something like this?

irb(main):001:0> class Object
irb(main):002:1> def method_missing meth_id
irb(main):003:2> nil
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> a = String.new
=> “”
irb(main):007:0> a.blah
=> nil
irb(main):008:0> a.blah.whatever
=> nil
irb(main):009:0> a.length
=> 0
irb(main):010:0> a.length.whatever
=> nil
irb(main):011:0>

HTH,

Felix

On Aug 18, 2007, at 2:36 PM, John W. wrote:

def bar = foo?.something?.myMethod()
assert bar == null

Is there an easy way to hack an equivalent out in Ruby?

Sure, NilClass can be reopened just fine:

class NilClass
def method_missing(name, *args)
nil
end
end

nil.invoices.find(5) # -> nil

Reopening NilClass is something really handy sometimes.

– fxn

John W. wrote:

Is there an easy way to hack an equivalent out in Ruby?
irb(main):001:0> def nil.method_missing(*_) end
=> nil
irb(main):002:0> nil.a.b.c
=> nil

Cheers,
Dave

On Aug 18, 2007, at 2:55 PM, Arlen Christian Mart C. wrote:

The only problem I can see here is that it’s not quite optional.

Yeah, that’s the basic technique.

You could use some naming convention as in Groovy as well (which you
would check in the body of method_missing), or perhaps wrap the
activation of that catchall in a block like this:

with_safe_navigation do
regular code
end

Once you can reopen NilClass like that I think there are ways to
emulate that feature.

– fxn

Sure, NilClass can be reopened just fine:

class NilClass
def method_missing(name, *args)
nil
end
end

nil.invoices.find(5) # -> nil

The only problem I can see here is that it’s not quite optional.

Arlen

2007/8/20, Robert K. [email protected]:

  instance_eval(&b)

end
robert
PS: Forgot to mention: you can always use the “rescue” modifier:

x = foo.bar.baz rescue nil

John W. wrote:

Guys,

There’s something called Safe Navigation in Groovy
(http://groovy.codehaus.org/Statements#Statements-Safenavigation) that I
find very appealing.

So, Groovy will allow you to safely walk an object graph, even if that
graph has nulls in it (the walk will short circuit):

def foo = null
def bar = foo?.something?.myMethod()
assert bar == null

Is there an easy way to hack an equivalent out in Ruby?

Thanks,
John

Good to see that I’m not alone on this :slight_smile:
I still intend to write an RCR for this. You might want to read through
http://www.ruby-forum.com/topic/115720

Regards
Stefan

On Aug 20, 2007 4:07 AM, Robert K. [email protected]
wrote:

x = foo.bar.baz rescue nil

Interesting thread…glad someone else has hit this need.

How does the above work, exactly? You’re rescuing without a block?
Doesn’t it have to be something like:

begin
x = foo.bar.baz
rescue nil
end

? At least the documentation would suggest so…

Thanks,
Jake

2007/8/18, John W. [email protected]:

Is there an easy way to hack an equivalent out in Ruby?
Try this in IRB

class Object
class Holder
def __ref() @ref end

def initialize(ref,&b)
  @ref = ref
  instance_eval(&b)
end

def method_missing(s,*a,&b)
  @ref = @ref.send(s,*a,&b) rescue nil
  self
end

end

def safe(&b)
Holder.new(self,&b).__ref
end
end
F = Struct.new :name
f=F.new “foo”
f.safe { name.size > 10 }
f.safe { name.xxx }

Not too nice though…

Kind regards

robert

On 21.11.2007 18:24, Jake C. wrote:

rescue nil
end

? At least the documentation would suggest so…

The value of the expression is replaced by the value of the expression
after the “rescue” in this form. And no, you don’t need a block. The
Pickaxe 1st edition does not seem to mention it but it’s definitively a
legal Ruby feature.

Kind regards

robert

On Nov 21, 2007, at 2:40 PM, Robert K. wrote:

The value of the expression is replaced by the value of the
expression after the “rescue” in this form. And no, you don’t need
a block. The Pickaxe 1st edition does not seem to mention it but
it’s definitively a legal Ruby feature.

Begin-Rescue-End blocks tend to slow things down significantly - does
JUST including rescue also take those penalties to speed?

  • Ari B.

On Nov 21, 2007, at 2:47 PM, thefed wrote:

Begin-Rescue-End blocks tend to slow things down significantly -
does JUST including rescue also take those penalties to speed?

Sebastian D. did some benchmarking on this last year.

http://www.notsostupid.com/blog/2006/08/31/the-price-of-a-rescue/

His conclusions: “Using rescue is not much more expensive than running
naked. In my tests in particular, it never was more than 5% slower. It
might even be cheaper than multiple tests.”

Cheers from NYC,
Luke

On Nov 21, 2007 12:24 PM, Jake C. [email protected] wrote:

rescue nil
end

? At least the documentation would suggest so…

Thanks,
Jake

You don’t need begin unless you want to catch just a section of code.
Single
lines works wonders for concise error handling, such as

this_method_can_throw rescue “default value”

Or for a full method (Rails)

def action
does_stuff_that_can_throw
rescue
default_error_handling
end

Ruby’s awesome.

Jason

Luke M. wrote:

naked. In my tests in particular, it never was more than 5% slower. It
might even be cheaper than multiple tests."

It slows down JRuby a bit more than Ruby 1.8, unfortunately, because of
the way the JVM manages exception handling and operand stacks. But
generally you won’t notice it, since nontrivial code bodies will be
quite a bit faster than 1.8.

~/NetBeansProjects/jruby-current $ jruby -J-server test.rb
user system total real
plain 0.493000 0.000000 0.493000 ( 0.493000)
plain 0.474000 0.000000 0.474000 ( 0.474000)
plain 0.222000 0.000000 0.222000 ( 0.222000)
plain 0.220000 0.000000 0.220000 ( 0.220000)
plain 0.219000 0.000000 0.219000 ( 0.219000)
safe 0.431000 0.000000 0.431000 ( 0.431000)
safe 0.338000 0.000000 0.338000 ( 0.337000)
safe 0.320000 0.000000 0.320000 ( 0.320000)
safe 0.317000 0.000000 0.317000 ( 0.316000)
safe 0.319000 0.000000 0.319000 ( 0.319000)
rescue 0.315000 0.000000 0.315000 ( 0.315000)
rescue 0.313000 0.000000 0.313000 ( 0.313000)
rescue 0.314000 0.000000 0.314000 ( 0.314000)
rescue 0.312000 0.000000 0.312000 ( 0.312000)
rescue 0.312000 0.000000 0.312000 ( 0.313000)
~/NetBeansProjects/jruby-current $ ruby test.rb
user system total real
plain 0.210000 0.000000 0.210000 ( 0.214133)
plain 0.210000 0.000000 0.210000 ( 0.228721)
plain 0.200000 0.000000 0.200000 ( 0.206997)
plain 0.210000 0.000000 0.210000 ( 0.206290)
plain 0.200000 0.010000 0.210000 ( 0.205982)
safe 0.240000 0.000000 0.240000 ( 0.238373)
safe 0.230000 0.000000 0.230000 ( 0.243327)
safe 0.240000 0.000000 0.240000 ( 0.237573)
safe 0.230000 0.000000 0.230000 ( 0.242121)
safe 0.240000 0.000000 0.240000 ( 0.237385)
rescue 0.230000 0.000000 0.230000 ( 0.238207)
rescue 0.230000 0.000000 0.230000 ( 0.235387)
rescue 0.230000 0.000000 0.230000 ( 0.234333)
rescue 0.240000 0.000000 0.240000 ( 0.234938)
rescue 0.230000 0.000000 0.230000 ( 0.240186)

  • Charlie

On Nov 23, 2007 10:07 AM, Charles Oliver N. [email protected]
wrote:

may go away.

  • Charlie

It seems however that the rescue clause is not part of Ruby1.9
anymore, maybe, if this is confirmed, you might not want to optimize
this.

Cheers
Robert

Charles Oliver N. wrote:

It slows down JRuby a bit more than Ruby 1.8, unfortunately, because of
the way the JVM manages exception handling and operand stacks. But
generally you won’t notice it, since nontrivial code bodies will be
quite a bit faster than 1.8.

Actually, it just occurred to me that this is entirely a factor of local
variable handling; when rescue is involved, JRuby has to switch from
stack-based local variables to heap-based local vars. I’m working on a
few ways to mitigate this cost for the general case, so this perf hit
may go away.

  • Charlie

On 11/23/07, Robert D. [email protected] wrote:

It seems however that the rescue clause is not part of Ruby1.9
anymore, maybe, if this is confirmed, you might not want to optimize
this.

You mean the one line rescue syntax mentioned before? Interesting, I
can’t find any docs via Google on this being removed in 1.9. Where are
you finding this info?

Seems strange that such a useful feature would be removed…

On Nov 23, 2007 3:11 PM, John W. [email protected] wrote:

On 11/23/07, Robert D. [email protected] wrote:

It seems however that the rescue clause is not part of Ruby1.9
anymore, maybe, if this is confirmed, you might not want to optimize
this.

You mean the one line rescue syntax mentioned before? Interesting, I
can’t find any docs via Google on this being removed in 1.9. Where are
you finding this info?
From Ruby 1.9 itself :wink:
I thought, :frowning:

But I just cross checked and it works like charm.

Very sorry about the noise.

Cheers
Robert