coercing nil/obj to false/true

S

Steve Howell

I know this probably comes up a lot, but I could not Google the exact
question as I'm formulating it.

Is there a way to avoid this idiom?

def is_there_one(whatever)
!some_call_to_lib_that_returns_object_or_nil(whatever).nil?
end

The above code tersely coerces a result to a boolean value, but it's
hard to read, because it's a double negative, and the "!" negative is
lexically separated from the "nil?" negative.

I occasionally do this instead:

x = some_call_to_lib_that_returns_object_or_nil
x.nil?

That's more readable for me, but more verbose, and I can never decide
what to name "x."

I can add something like this to my codebase, but I'm wondering if
something similar is already built in:

def to_boolean x
return !x.nil?
end

def is_there_an_x_like(whatever)
to_boolean(some_call_to_lib_x_that_returns_object_or_nil(whatever))
end

def is_there_a_y_like(whatever)
to_boolean(some_call_to_y_lib_that_returns_object_or_nil(whatever))
end

Finally, I can just have my method return obj or nil, and let the
callers use it in boolean expressions, but my fear there is that I set
the wrong expectation for the caller, if I later return a different
object, when my intention is only to indicate whether a query succeeds
or not. (You guessed it, this is motivated by ActiveRecord, but it's
really a Ruby question.)

Thoughts?
 
R

Robert Klemme

2010/3/30 Steve Howell said:
Is there a way to avoid this idiom?

def is_there_one(whatever)
=A0!some_call_to_lib_that_returns_object_or_nil(whatever).nil?
end
Finally, I can just have my method return obj or nil, and let the
callers use it in boolean expressions, but my fear there is that I set
the wrong expectation for the caller, if I later return a different
object, when my intention is only to indicate whether a query succeeds
or not. =A0(You guessed it, this is motivated by ActiveRecord, but it's
really a Ruby question.)

Your method's documentation and naming the method with a question mark
at the end will help avoid this. I would be more concerned with
leaking internal information. That's why people often do this in
order to force conversion to true / false:

def is_there_one? whatever
!! some_call_to_lib_that_returns_object_or_nil(whatever)
end

If the call is expensive then I'd just return whatever is found and
let the caller check for nil in one of the many ways.

Btw, databases typically return always a collection - albeit it might
be empty. That depends on your mechanics in the invoked method of
course.

Kind regards

robert

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

Phrogz

I can add something like this to my codebase, but I'm wondering if
something similar is already built in:

def to_boolean x
    return !x.nil?
end

If you really, really need exactly true or false based on the
truthiness of the value, just do:
!!x

However, I would have all your methods return either a useful value or
nil (or when appropriate, false), and just use that value in all your
boolean expressions.

For example, imagine an array-based stack. You could write:
def top?
!self.last.nil?
end
but I would instead recommend just writing:
def top
self.last
end
and let your users do:
if recent = my_stack.top
# do something with recent
end
 
S

Steve Howell

Your method's documentation and naming the method with a question mark
at the end will help avoid this.  I would be more concerned with
leaking internal information.  
Yep.

That's why people often do this in
order to force conversion to true / false:

def is_there_one? whatever
  !! some_call_to_lib_that_returns_object_or_nil(whatever)
end

Ok, thanks, I find that more readable than !foo.nil?.
If the call is expensive then I'd just return whatever is found and
let the caller check for nil in one of the many ways.

Btw, databases typically return always a collection - albeit it might
be empty.  That depends on your mechanics in the invoked method of
course.

Yep, understood, but ActiveRecord returns nil or object when you pass
find the :first parameter. It's useful in some situations where you
just want to check that a record has at least one active child,
without caring about the children themselves, such as when you are
cleaning up "parent" objects that have been orphaned.
 
R

Rick DeNatale

Your method's documentation and naming the method with a question mark
at the end will help avoid this. =A0I would be more concerned with
leaking internal information. =A0That's why people often do this in
order to force conversion to true / false:

def is_there_one? whatever
=A0!! some_call_to_lib_that_returns_object_or_nil(whatever)
end

I almost never find that I need to 'force' a 'true' boolean value in Ruby.

I pretty much agree with Koz about this.
http://www.therailsway.com/2007/8/1/dangers-of-cargo-culting

--=20
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top