Check existence of object and it's property at the same time

I run into this from time to time and I was wondering if there is a
cleaner way to do check that an object is not nil and also check a
property of that object.

I want to do this:

if !@member.nil? and @member.is_active?
  ... do something ...
else
  ... do something else ...
end

But this obviously raises a no method error if @member is nil.

I end up having to do:

if !@member.nil?
  if @member.is_active?
    ... do something ...
  else
    ... do something else ...
  end
end

I know it isn't that much more verbose, but does ruby have a more
elegant way of handling this?

···

--
Posted via http://www.ruby-forum.com/.

Hi --

I run into this from time to time and I was wondering if there is a
cleaner way to do check that an object is not nil and also check a
property of that object.

I want to do this:

if !@member.nil? and @member.is_active?
... do something ...
else
... do something else ...
end

But this obviously raises a no method error if @member is nil.

It doesn't, actually, because if @member is nil, the "and" is
short-circuited so the right-hand expression doesn't get evaluated:

if !@member.nil? and @member.is_active?; end

=> nil

@member

=> nil

A somewhat more common way of doing this is:

   if @member && @member.is_active? ... end

There's a difference, though, which is that "if @member" is false if
@member is false, not just if @member is nil. I'm a big non-fan of
tri-state booleans involving true/false/nil, so I try to avoid
situations where I have to distinguish between nil and false for
condition-testing purposes.

David

···

On Thu, 19 Aug 2010, Cory Patterson wrote:

--
David A. Black, Senior Developer, Cyrus Innovation Inc.

   The Ruby training with Black/Brown/McAnally
   Compleat Philadelphia, PA, October 1-2, 2010
   Rubyist http://www.compleatrubyist.com

I've run into a similar situation before, and found that
short-circuiting in an 'if' statement is inconsistent.

For instance, this will short-circuit and prevent evaluation of
subsequent statements if the first one is false (which is desired
obviously):

unless creds.class.to_s =~ /Hash/ && creds.has_key?("user") && ...

But this won't:

unless creds.instance_of?(Hash) && creds.has_key?("user") && ...

I'd be interested to learn why the first one short-circuits and the
second doesn't. Anyone have any insight?

Thanks,
Alex

···

On Wed, 2010-08-18 at 16:09 -0500, Cory Patterson wrote:

I run into this from time to time and I was wondering if there is a
cleaner way to do check that an object is not nil and also check a
property of that object.

I want to do this:

if !@member.nil? and @member.is_active?
  ... do something ...
else
  ... do something else ...
end

But this obviously raises a no method error if @member is nil.

I end up having to do:

if !@member.nil?
  if @member.is_active?
    ... do something ...
  else
    ... do something else ...
  end
end

I know it isn't that much more verbose, but does ruby have a more
elegant way of handling this?

Hi --

I've run into a similar situation before, and found that
short-circuiting in an 'if' statement is inconsistent.

For instance, this will short-circuit and prevent evaluation of
subsequent statements if the first one is false (which is desired
obviously):

unless creds.class.to_s =~ /Hash/ && creds.has_key?("user") && ...

But this won't:

unless creds.instance_of?(Hash) && creds.has_key?("user") && ...

They both short-circuit. Note that the puts("here") statement never gets
executed.

creds = {}

=> {}

unless creds.class.to_s =~ /Hash/ && creds.has_key?("user") && puts("here"); 1; end

=> 1

unless creds.instance_of?(Hash) && creds.has_key?("user") && puts("here"); 1; end

=> 1

David

···

On Thu, 19 Aug 2010, Alex Stahl wrote:

--
David A. Black, Senior Developer, Cyrus Innovation Inc.

   The Ruby training with Black/Brown/McAnally
   Compleat Philadelphia, PA, October 1-2, 2010
   Rubyist http://www.compleatrubyist.com

David,

You are completely correct. I guess that was a bad example. So the
order of the conditions is important:

if @member and @member.is_active?; end

=> nil

if @member.is_active? && @member; end

NoMethodError: undefined method `is_active?' for nil:NilClass

I could have sworn I ran into this somewhere and it didn't work as
expected.

Thanks so much for the insight, it is good information to have.

Cory

David A. Black wrote:

···

Hi --

On Thu, 19 Aug 2010, Cory Patterson wrote:

end

But this obviously raises a no method error if @member is nil.

It doesn't, actually, because if @member is nil, the "and" is
short-circuited so the right-hand expression doesn't get evaluated:

if !@member.nil? and @member.is_active?; end

=> nil

@member

=> nil

A somewhat more common way of doing this is:

   if @member && @member.is_active? ... end

There's a difference, though, which is that "if @member" is false if
@member is false, not just if @member is nil. I'm a big non-fan of
tri-state booleans involving true/false/nil, so I try to avoid
situations where I have to distinguish between nil and false for
condition-testing purposes.

David

--
David A. Black, Senior Developer, Cyrus Innovation Inc.

   The Ruby training with Black/Brown/McAnally
   Compleat Philadelphia, PA, October 1-2, 2010
   Rubyist http://www.compleatrubyist.com

--
Posted via http://www.ruby-forum.com/.

(P.S. I've made the second condition fail, rather than the first, but if
you make creds a non-hash it will short-circuit after the first one.)

···

On Thu, 19 Aug 2010, David A. Black wrote:

Hi --

On Thu, 19 Aug 2010, Alex Stahl wrote:

I've run into a similar situation before, and found that
short-circuiting in an 'if' statement is inconsistent.

For instance, this will short-circuit and prevent evaluation of
subsequent statements if the first one is false (which is desired
obviously):

unless creds.class.to_s =~ /Hash/ && creds.has_key?("user") && ...

But this won't:

unless creds.instance_of?(Hash) && creds.has_key?("user") && ...

They both short-circuit. Note that the puts("here") statement never gets
executed.

creds = {}

=> {}

unless creds.class.to_s =~ /Hash/ && creds.has_key?("user") && puts("here"); 1; end

=> 1

unless creds.instance_of?(Hash) && creds.has_key?("user") && puts("here"); 1; end

=> 1

--
David A. Black, Senior Developer, Cyrus Innovation Inc.

   The Ruby training with Black/Brown/McAnally
   Compleat Philadelphia, PA, October 1-2, 2010
   Rubyist http://www.compleatrubyist.com

David,

You are completely correct. I guess that was a bad example. So the
order of the conditions is important:

if @member and @member.is_active?; end

=> nil

if @member.is_active? && @member; end

NoMethodError: undefined method `is_active?' for nil:NilClass

Yes, it's important. Ruby starts evaluating from left to right, and
will shortcircuit on the first value that would make the whole
expression false (or true if it's an "or").

irb(main):004:0> member = nil
=> nil
irb(main):005:0> if member or member.is_active?
irb(main):006:1> puts "one or both were true"
irb(main):007:1> end
NoMethodError: undefined method `is_active?' for nil:NilClass
  from (irb):5
irb(main):008:0> member = "test"
=> "test"
irb(main):009:0> if member or member.is_active?
irb(main):010:1> puts "one or both were true"
irb(main):011:1> end
one or both were true

Here you have the opposite situation: when the first truthy expression
is found, the evaluation is shortcircuited to that value, as you can
see that the is_active? method is not called in the last example.

Jesus.

···

On Wed, Aug 18, 2010 at 11:47 PM, Cory Patterson <coryp@aquasun.com> wrote:
  from :0

Strange... it was failing before (like a few weeks ago) w/ a
NoMethodError on has_key? when it wasn't a hash. But trying it again
now works fine as you note.

···

On Wed, 2010-08-18 at 16:33 -0500, David A. Black wrote:

On Thu, 19 Aug 2010, David A. Black wrote:

> Hi --
>
> On Thu, 19 Aug 2010, Alex Stahl wrote:
>
>> I've run into a similar situation before, and found that
>> short-circuiting in an 'if' statement is inconsistent.
>>
>> For instance, this will short-circuit and prevent evaluation of
>> subsequent statements if the first one is false (which is desired
>> obviously):
>>
>> unless creds.class.to_s =~ /Hash/ && creds.has_key?("user") && ...
>>
>>
>> But this won't:
>>
>> unless creds.instance_of?(Hash) && creds.has_key?("user") && ...
>
> They both short-circuit. Note that the puts("here") statement never gets
> executed.
>
>>> creds = {}
> => {}
>>> unless creds.class.to_s =~ /Hash/ && creds.has_key?("user") &&
>>> puts("here"); 1; end
> => 1
>>> unless creds.instance_of?(Hash) && creds.has_key?("user") && puts("here");
>>> 1; end
> => 1

(P.S. I've made the second condition fail, rather than the first, but if
you make creds a non-hash it will short-circuit after the first one.)

For the record: short circuiting also happens in Enumerable#any? and
#all?. And btw, the same short circuiting is done in Java and I guess
most modern languages.

Kind regards

robert

···

2010/8/19 Jesús Gabriel y Galán <jgabrielygalan@gmail.com>:

On Wed, Aug 18, 2010 at 11:47 PM, Cory Patterson <coryp@aquasun.com> wrote:

David,

You are completely correct. I guess that was a bad example. So the
order of the conditions is important:

if @member and @member.is_active?; end

=> nil

if @member.is_active? && @member; end

NoMethodError: undefined method `is_active?' for nil:NilClass

Yes, it's important. Ruby starts evaluating from left to right, and
will shortcircuit on the first value that would make the whole
expression false (or true if it's an "or").

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Hi --

···

On Thu, 19 Aug 2010, Alex Stahl wrote:

Strange... it was failing before (like a few weeks ago) w/ a
NoMethodError on has_key? when it wasn't a hash. But trying it again
now works fine as you note.

Maybe you were doing has_key? first. Unless you did this:

   h = {}
   class << h; undef_method :has_key?; end

:slight_smile:

David

--
David A. Black, Senior Developer, Cyrus Innovation Inc.

   The Ruby training with Black/Brown/McAnally
   Compleat Philadelphia, PA, October 1-2, 2010
   Rubyist http://www.compleatrubyist.com