tags:

views:

207

answers:

6

I frequently find myself doing this:

!(val).nil?

My code would be prettier if there was a method like

val.exists?

Is there something like that?

+10  A: 

you can use the unless statement, eg,

do_something unless val.nil?

which is probably pretty close to the ideal way to phrase it: if you had a non_nil? method you'd have a negated statement instead of a positive statement like this one.

Peter
This is how I do it as well.
Chuck Vose
+4  A: 
if !val.nil?
  # do something
end

# is equivalent to

if val
  # do something
end

If you are using Rails, ActiveSupport provides two Object extensions called Object#blank? and Object#present?.

if !address.nil? && !address.empty?
# becomes
if !address.blank?
# which becomes
if address.present?
Simone Carletti
this won't work if `val` is a boolean - `false` will mistakenly be treated the same as `nil`.
Peter
Damn, good catch. I was about to post this same answer.
Chuck Vose
It's unlikely he's testing a (possible) Boolean for nil, since you don't do anything but check the truth value anyway.
klochner
@klochner I coldn't say better. Peter's comment doesn't make sense to me.
Simone Carletti
let's say `val` is a flag that indicates whether something is true or false. before checking some condition, `val` will be `nil`, but after checking the condition, `val` becomes `true` or `false`. this is the 'unlikely' case that `val` is `nil` before becoming `true` or `false`.
Peter
I'll grant that it's possible, just unlikely. More likely he's trying to avoid an exception when subsequently calling val.foo or val["foo"]
klochner
Peter, I know that it's possible but that sounds a bad design to me. If you have a variable `condition` supposed to be a boolean flag, you should either initialize it or thread it as boolean.
Simone Carletti
+1  A: 

!!val

klochner
+1 though this might be harder for readability, but I really hope it becomes an idiom.
bryantsai
This does not work, as !!false is false, this is different than !false.nil?
cwninja
@cwninja - see the comment thread above.
klochner
+2  A: 

It's worth noting that !val.nil? is a code smell indicating that there might be a better way to do what you're trying to do; perhaps the code is relying on a datastructure which could be replaced by something which could handle the edge cases better.

Here's an example of one way .nil? might be being used poorly:

For instance:

blah = {}
[:a,:b,:c,:a].each do |l|
     if blah[l].nil?
         blah[l] = 0
     else
         blah[l] += 1
     end
end
blah #=> {:a => 2, :b => 1, :c =>1}

Could potentially be rewritten as

blah = Hash.new(0)
[:a,:b,:c,:a].each{|i| blah[i] += 1} #or with inject.

The ||= operator is another area to look into.


REDACTED: A common idiom for doing something with a value which could be nil is using the && operator, since nil is falsy, so instead of

if !val.nil?
   val.do_something
end

It's common to just write

val && val.do_something # =>nil if val is nil, val.do_something's value otherwise

This requires just as much knowledge about the way nil is handled in boolean expressions as is required for mckeed's (x if y) conditional example below, so it doesn't really help the code read better.

Tim Snowhite
mckeed
I agree, but I'd also say that:`blah = val.do_something if val` is confusing if you don't realize there's an implicit `else nil` there. So your example is good, but looks strange if the return value of `val.do_something` is what's desired.I think the code smell is the biggest issue here, I'll edit my answer to highlight it better.
Tim Snowhite
Tim Snowhite
A: 
module Nonnil
  def non_nil?
    !(self.nil?)
  end
end

class Someclass
  include Nonnil
  extend Nonnil
end

This will add the member .non_nil? to the class Someclass, defined as the inverse of .nil?. Mix this module into the class that 'val' (in your example) belongs to and you will have a handy shortcut. Mix this into class Object and it will be available for every class (since Object is the parent of all classes).

bta
A: 

No – but you could write one?

cwninja