The Ruby Way to build an object unless nil?

Hello all,

I have this :

def mymethod
  a = someobjectreference('a')
  if a.nil?
    return nil
  end
  b = a.someattribute_might_be_nil
  if b.nil?
    return nil
  end
  c = b.someattribute_might_be_nil
  if c.nil?
    return nil
  end
  c.dosomething
end

What is the ruby way to handle the if .nil? ladder created here?

Thanks.
Peter Fitzgibbons

I'm not sure what the ideal is, but this is certainly more terse:

def mymethod
  a = someobjectreference('a')
  b = a.some_attribute unless a.nil?
  c = b.some_attribute unless b.nil?
  c.dosomething unless c.nil?
end

If any of those are nil, the rest of the statements will evaluate to
nil as well.

This could be accomplished using a recursive method. It is more resource intensive than what you have here, but it would end up being simpler and more versatile.

def mymethod(a, count=1)
  return if a.nil?
  return c.dosomething if count == 3
  mymethod(a.someattribute_might_be_nil, count+1)
end

Peter Fitzgibbons wrote:

···

Hello all,

I have this :

def mymethod
  a = someobjectreference('a')
  if a.nil?
    return nil
  end
  b = a.someattribute_might_be_nil
  if b.nil?
    return nil
  end
  c = b.someattribute_might_be_nil
  if c.nil?
    return nil
  end
  c.dosomething
end

What is the ruby way to handle the if .nil? ladder created here?

Thanks.
Peter Fitzgibbons

One possibility:

  def mymethod(a = nil)
    a.attr1.attr2.do_something
  rescue NoMethodError
    return nil
  end

You may want to disambiguate the NoMethod error to make sure it's not
raised in #do_something:

  def mymethod(a = nil)
    c = a.attr1.attr2 rescue return nil
    c.do_something
  end

-austin

···

On 10/18/05, Peter Fitzgibbons <peter.fitzgibbons@gmail.com> wrote:

Hello all,

I have this :

def mymethod
  a = someobjectreference('a')
  if a.nil?
    return nil
  end
  b = a.someattribute_might_be_nil
  if b.nil?
    return nil
  end
  c = b.someattribute_might_be_nil
  if c.nil?
    return nil
  end
  c.dosomething
end

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

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

Forget the ladder... use the elevator! :wink:

-J()by
http://jobybednar.com

How about:

def mymethod
   if
   a = someobjectreference('a') and
   b = a.someattribute_might_be_nil and
   c = b.someattribute_might_be_nil
     c.dosomething
   else
     nil
   end
end

It isn't exactly the same, because it would also return nil if a, b or c were false instead of nil.

Dominik

···

On Tue, 18 Oct 2005 20:34:05 +0200, Peter Fitzgibbons <peter.fitzgibbons@gmail.com> wrote:

Hello all,

I have this :

def mymethod
  a = someobjectreference('a')
  if a.nil?
    return nil
  end
  b = a.someattribute_might_be_nil
  if b.nil?
    return nil
  end
  c = b.someattribute_might_be_nil
  if c.nil?
    return nil
  end
  c.dosomething
end

class NilObject
   def someattribute
     nil
   end

   def dosomething
     nil
   end
end

def mymethod
   someobjectrefence('a').someattribute.someattribute.dosomething
end

John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand

Carter's Clarification of Murphy's Law.

"Things only ever go right so that they may go more spectacularly wrong later."

From this principle, all of life and physics may be deduced.

···

On Wed, 19 Oct 2005, Peter Fitzgibbons wrote:

def mymethod
a = someobjectreference('a')
if a.nil?
   return nil
end
b = a.someattribute_might_be_nil
if b.nil?
   return nil
end
c = b.someattribute_might_be_nil
if c.nil?
   return nil
end
c.dosomething
end

Not quite a direct response, but the ||= idiom is also handy for these
things
ie:

irb(main):001:0> a = nil
irb(main):002:0> b = 4
irb(main):003:0> b ||= 7
=> 4
irb(main):004:0> b
=> 4
irb(main):005:0> a ||= b
=> 4
irb(main):006:0> a
=> 4

  .adam

Thank you Kevin. I knew I was missing the obvious.

···

On 10/18/05, Kevin Ballard <kballard@gmail.com> wrote:

I'm not sure what the ideal is, but this is certainly more terse:

def mymethod
a = someobjectreference('a')
b = a.some_attribute unless a.nil?
c = b.some_attribute unless b.nil?
c.dosomething unless c.nil?
end

If any of those are nil, the rest of the statements will evaluate to
nil as well.

I like that when I'm only concerned with the final value (e.g. in an erb template)
   <%= foo.bar.baz rescue nil %>

otherwise,
   if a = foo and b = a.bar then b.baz end

Regards,
jeremy

···

On Oct 18, 2005, at 12:14 PM, Austin Ziegler wrote:

One possibility:
  def mymethod(a = nil)
    a.attr1.attr2.do_something
  rescue NoMethodError
    return nil
  end

How about:

module Kernel
   def send_each(*mlist)
     mlist.inject(self) do |obj, mname|
         return nil unless obj
         obj.send(mname)
     end
   end
end

puts "ruby rocks".send_each(:reverse, :chop, :capitalize) # -> "Skcor ybu"

Gary Wright

···

On Oct 18, 2005, at 2:42 PM, Kevin Ballard wrote:

I'm not sure what the ideal is, but this is certainly more terse:
def mymethod
  a = someobjectreference('a')
  b = a.some_attribute unless a.nil?
  c = b.some_attribute unless b.nil?
  c.dosomething unless c.nil?
end

Joby Bednar wrote:

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

Forget the ladder... use the elevator! :wink:

While that certainly works, I would advise not doing that. The problem
with this is it will hide problems that might show up elsewhere in your
code.

Sorry, that should be NilClass

John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand

Carter's Clarification of Murphy's Law.

"Things only ever go right so that they may go more spectacularly wrong later."

From this principle, all of life and physics may be deduced.

···

On Wed, 19 Oct 2005, John Carter wrote:

class NilObject

Well, IF you actually want to debug... true... it could cause some
problems, though you could also put in some debug logging or such
before returning nil. But, with this method (a little pun there) you
can place nil catching at major gatekeeper points in the code instead
of on every line where a nil might be returned. Especially when one
line would be broken out into numerous.

-J()by
http://jobybednar.com

Nice, but your example is no different to

  puts "ruby rocks".reverse.chop.capitalize

Maybe this shows off your method better:

class String
  def nil_method
    nil
  end
end
puts "ruby rocks".send_each(:reverse, :chop, :nil_method, :capitalize)
  # -> nil

Regards,

Sean

···

On 10/18/05, gwtmp01@mac.com <gwtmp01@mac.com> wrote:

How about:

module Kernel
  def send_each(*mlist)
    mlist.inject(self) do |obj, mname|
        return nil unless obj
        obj.send(mname)
    end
  end
end

puts "ruby rocks".send_each(:reverse, :chop, :capitalize) # ->
"Skcor ybu"

I also think you shouldn't overload the semantics of "nil"
anymore. It already has enough meaning. Use another object
(like below), or just check for nil explicitly like most other
do.

What I do when I need this kind of functionality is just make a
"do nothing" object that just returns self for everything.
Then your callers just pass this when they want to do nothing
for that object:

Nothing = Class.new {
  def method_missing(method, *args, &block)
    self
  end
}.new

An example is that I have a method that takes a buffer object
where I store results. Sometimes I don't need the buffer, so I
just pass it something like the above.

···

--- Kevin Ballard <kballard@gmail.com> wrote:

Joby Bednar wrote:
> class NilClass
> def method_missing(method, *args)
> nil
> end
> end
>
> Forget the ladder... use the elevator! :wink:

While that certainly works, I would advise not doing that.
The problem
with this is it will hide problems that might show up
elsewhere in your
code.

__________________________________
Yahoo! Music Unlimited
Access over 1 million songs. Try it free.
http://music.yahoo.com/unlimited/

Yes yes we have had this on out all before... The answer is nil is overloaded to mean several things. eg. Not initialized and Not Applicable.

So how about..

class ReDuckulous
   # I just Quack myself up...
   def someattribute
     self
   end

   def dosomething
     self
   end
end

DAFFY = ReDuckulous.new

def mymethod
   a = somereference('a')
   a = DAFFY unless a # What's up Doc?
   a.someattribute.someattribute.dosomething
end

John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand

Carter's Clarification of Murphy's Law.

"Things only ever go right so that they may go more spectacularly wrong later."

From this principle, all of life and physics may be deduced.

···

On Wed, 19 Oct 2005, Kevin Ballard wrote:

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

Forget the ladder... use the elevator! :wink:

While that certainly works, I would advise not doing that. The problem
with this is it will hide problems that might show up elsewhere in your
code.