nil, nil?, true and false in Ruby
A friend of mine I'm teaching Ruby to asked me just a few days ago about the difference between nil and false and nil and nil? in Ruby. I gave him a very short answer:
nil = null
false = boolean value
nil? is a method
yes, I kinda lied to him about the null and false, but here is the long answer:
First of all, in order to understand how nil, true and false works you have to know that in Ruby:
- Every expression evaluates to false or true
- Every object evaluates to false or true.
conclusions:
- Expressions and objects never evaluates to nil
- nil and false are different each other
so, we all know that true and false are boolean values but what is nil and nil? anyway?
nil represents the nothing, null, None; some books say that it's the emptiness, I don't like to use that term because it sounds to me like it represents an empty string or an empty object and that isn't the case at all.
nil? is a method, more precisely, it's an instance method of the Object class, it's like asking "is my_object nil?":
NOTE: "expression/object # => value" means that such "expression" or "object" returns such "value".
my_object = nil foo = "baz" my_object.nil? # => true foo.nil? # => false
Second, there's a big difference between the object's value and the value an object evaluates to:
- The value of
nilis nil - The value of
falseis false - The value of
trueis true
nilevaluates to falsefalseevaluates to falsetrueand everything, everything, everything else evaluates to true
Let's see some examples:
bar = "silence is foo"
- The value of
baris "silence is foo" barevaluates to true
foo = ""
- The value of
foois an empty string fooevaluates to true
baz = 0
- The value of
bazis zero bazevaluates to true
qux = nil
- The value of
quxis nil quxevaluates to false
corge = false
- The value of
corgeis false corgeevaluates to false
That's why we don't need to do things like:
my_object = nil if !my_object.nil? puts "my_object is not nil" end if my_object == nil ... end if my_object != nil puts "my_object is not nil" end
Since we know nil evaluates to false, we'd do instead:
if my_object #it won't hit this part end unless my_object #it'll hit this part end
you should be aware that if you need to know if an object is exactly nil the code above won't help you in some cases. Look:
my_object = false
unless my_object
puts "my_object evaluates to false but we don't know if it's nil OR false"
end
unless my_object.nil?
puts "we certainly know that my_object is not nil"
end
my_object = nil
if my_object.nil?
puts "we certainly know that my_object is nil, anything else"
end
Let's see another case now with hashes, don't do this:
my_hash = {:name => "Ruby" }
my_hash[:version] # => nil (if a key doesn't exist in a hash it will return nil)
if !my_hash[:version].nil?
puts "The version is #{my_hash[:version]}"
end
if my_hash[:version] != nil
puts "The version is #{my_hash[:version]}"
end
if my_hash[:version] == nil
...
end
Instead we should do:
if my_hash
puts "even an empty hash will evaluate to true"
end
if my_hash.nil?
puts "you won't see this"
end
unless my_hash
puts "you won't see this"
end
unless my_hash.nil?
puts "we certainly know that my_hash is not nil and it is not false."
end
if my_hash[:version]
puts "you won't see this
else
puts "hash[:version] doesn't exist"
end
unless my_hash[:version]
puts ":version key doesn't exists"
end
if my_hash[:name]
puts "we know my_hash has a :name key"
end
Cool! now I have to say a last thing.
In Ruby, the value every object evaluates to is not a native boolean value it's actually an object.
meaning, nil, false and true are not simple keywords but objects and every object is instance of a class, in this case:
nilis instance of NilClassfalseis instance of FalseClasstrueis instance of TrueClass
A real world example of why is this very useful? What about the Whiny Nils in Ruby on Rails?.
oh, yeah, but why nil and false, why don't just false?
false and true are used in boolean expressions and nil is the value a method returns when something went wrong or when there's nothing to return, pretty different than false, don't you think?
Let's see some examples:
puts "foo" # => nil
The Kernel#puts method prints the given string in the STDOUT and returns nil, why we would want Kernel#puts to return false after all? Of course, there's a lot of methods that returns nil in the same fashion, like Regexp#match.
"foo" == "foo" # => true "foo" == "bar" # => false nil.nil? # => true
That's all folks, please, don't be shy, leave a comment.
Thanks for reading!
[Ruby Idioms] What is the splat/unary/asterisk operator useful for?
Long story short: the splat operator is useful to explode and flatten arrays and hashes (enumerables).
Doesn't sound like something powerful, does it?
Code is worth a thousand words.
1. Passing a variable number of arguments to a method
Let's get started with an hypothetical method called ActiveRecord::Base#find. Please, don't care about the functionality but the method signature.
def find(*args)
...
[args, args.class]
end
find # => [[], Array]
find(:all) # => [[:all], Array]
find(:all, :select => "name") # => [[:all, :select => "name"], Array]
find(:all, :select => "name", :conditions => [ "age > ?", 21], :limit => 10)
As you can see, the ActiveRecord::Base#find method accept a variable number of arguments, it's even able to be called without arguments, all of this thanks to the asterisk (splat) which initializes "args" as an empty array. Of course, the real ActiveRecord::Base#find method will raise an exception if you call it without arguments, but it's not a Ruby exception, it allows you to call the method without arguments.
Now let's see the ActionView::Helpers::TextHelper#highlight method:
def highlight(text, phrases, *args)
...
end
highlight("lorem ipsum") # => wrong number of arguments (1 for 2)
highlight("lorem ipsum", "ipsum") # => lorem <strong class="highlight">ipsum</strong> dolorem
highlight("lorem ipsum", "ipsum", :highlighter => <b>\1</b>) # => lorem <b>ipsum</b> dolorem
The highlight method uses the splat in the last argument to avoid to put the default highlighter in its signature, this way it's cleaner and it'd accept more options in the future without changing it.
In Ruby 1.8 the splat operator must be used only once per method and it must be used in the last argument, the only exception is when the last argument is a proc, like in the ActionView::Helpers::FormHelper#form_for method:
def form_for(record, *args, proc) ... end form_for :user # => syntax error, unexpected tIDENTIFIER, expecting tAMPER or '&'
In this case, Ruby 1.9.1 won't complain at all, in order to Ruby 1.8 accept this signature you must add an ampersand in the last argument:
def form_for(record, *args, &proc)
...
end
form_for @user
form_for @user { |form| ... }
In the last line we are passing the "record" and the "&proc" arguments, not the "args" one. So, inside the method, "args" is an empty array. Let's pass the three arguments.
form_for @user, :url => user_path(@user) { |form| ... }
form_for @user, :as => :person, :url => user_path(@user) { |form| ... }
record # => @user
*args # => :as => :person, :url => user_path(@user)
&proc # => { |form| ... }
2. Passing one array or hash as argument to a method expecting more than one arguments
Passing an array
def foo(bar, baz)
"bar is:" + bar + " and baz is: " + baz
end
my_ary = ["first", "second"]
foo *my_ary # => bar is: first and baz is: second
foo my_ary[0], my_ary[1] # => bar is: first and baz is: second
my_array = ["first", "second", "third"]
foo *my_array # => wrong number of arguments (3 for 2)
Passing a hash
def foo(bar, baz)
[bar,baz]
end
my_hash = { :first => 1, :second => 2 }
foo *my_hash # => [[:first, 1], [:second, 2]]
Consider the following case in Ruby 1.8
def foo(bar, baz, qux) [bar, baz, qux] end my_ary = ["first", "second"] foo *my_ary, "third" # => syntax error, unexpected tINTEGER, expecting tAMPER
now in Ruby 1.9.1
foo *my_ary, "third" # => ["first", "second", "third"]
3. Multiple variable assignment
In Ruby, you don't need the splat operator to do multiple variable assignment:
my_ary = [1,2,3] a, b, c = my_ary a # => 1 b # => 2 c # => 3
but you need it to do things like the following:
my_ary = [1,2,3] a, b = my_ary a # => 1 b # => 2 #we lose the third element! a, *b = my_ary a # => 1 b # => [2, 3]
Very nice!
A lot of methods in Ruby and Rails returns an array so you can take advantage of that fact and use the splat operator in a bunch of magic ways.
Well, now we know that the splat operator does, and that we can use it in methods, but it can be used in other scenarios as well:
4. Case/When
The following code is an extract of the ActiveRecord::Base#find method in Rails 3:
def find(*args)
...
case args.first
when :first, :last, :all
send(args.first)
else
find_with_ids(*args)
end
...
end
we can use the splat operator in the when clause this way:
def find(*args)
VALID_OPTIONS = :first, :last, :all # => [:first, :last, :all]
case args.first
when *VALID_OPTIONS
send(args.first)
else
find_with_ids(*args)
end
...
end
User.find(:last) # => send(:last) # => User.last
User.find(:all) # => send(:all) # => User.all
User.find(1) # => find_with_ids(1)
User.find(1,4,5,6) # => find_with_ids(1,4,5,6)
5. Array to Hash / Hash to Array
It sometimes comes in handy converting arrays into hashes and vice-versa, you might do it iterating the elements but there's a kind of shortcut to do it.
Array to Hash
my_ary = [[:first, 1], [:second, 2]] my_ary.flatten! # => [:first, 1, :second, 2] my_hash = Hash[*my_ary]
or even shorter
my_hash = Hash[*my_ary.flatten] # => {:first => 1, :second => 2}
my_hash[:first] # => 1
Hash to Array
my_hash = {:first => 1, :second = > 2}
my_ary = *my_hash # => [[:first, 1], [:second, 2]]
Let's see a real world example. The following code was taken from the Thin web server's spec_helper.rb
def parse_response(response)
raw_headers, body = response.split("\r\n\r\n", 2)
raw_status, raw_headers = raw_headers.split("\r\n", 2)
status = raw_status.match(%r{\AHTTP/1.1\s+(\d+)\b}).captures.first.to_i
headers = Hash[ *raw_headers.split("\r\n").map { |h| h.split(/:\s+/, 2) }.flatten ] <= HERE!
[ status, headers, body ]
end
Let's suppose we get a valid HTTP response:
foo_raw_response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: 16\r\nConnection: close\r\nServer: thin 1.2.5 codename This Is Not A Web Server\r\n\r\nThis is the BODY" parse_response(foo_raw_response)
This is the line I'd like you to focus in:
headers = Hash[ *raw_headers.split("\r\n").map { |h| h.split(/:\s+/, 2) }.flatten ]
"raw_headers" is a string we split by \r\n and then by the colon and we ended with an array.
raw_headers = "Content-Type: text/html\r\nContent-Length: 16\r\nConnection: close\r\nServer: thin 1.2.5 codename This Is Not A Web Server"
raw_headers # =>
[
[0] "Content-Type", <==== hash key
[1] "text/html", <==== hash value
[2] "Content-Length",
[3] "16",
[4] "Connection",
[5] "close",
[6] "Server",
[7] "thin 1.2.5 codename This Is Not A Web Server"
]
The parse_response method will return an array of size 3:
status, headers, body = parse_response(foo_raw_response)
status # => 200
body # => "This is the body"
headers # =>
{
"Content-Type" => "text/html",
"Content-Length" => "16",
"Connection" => "close",
"Server" => "thin 1.2.5 codename This Is Not A Web Server"
}
headers[:Content-Type] # => "text/html"
Cool, isn't it? well, we're almost done, let's see another important topic.
6. Object#to_a and Array#to_ary
The Object#to_a method returns an array representation of the receiver.
"string".to_a # => ["string"] 1.to_a # => [1] (1..5).to_a # => [1, 2, 3, 4, 5] [1,2,3].to_a # => [1,2,3]
The Array#to_ary method returns self, but of course it only works in arrays.
"string".to_ary # => undefined method 1.to_ary # => undefined method (1..5).to_ary # => undefined method [1,2,3].to_ary # => [1,2,3]
So we may say that if an object respond to to_ary we may be sure that such object is an array:
[1,2,3].respond_to? :to_ary # => true (it's an array) "string".respond_to? :to_ary # => false (it isn't an array)
But what would happen if we'd add a to_ary method to our own class?
Instances of our class would respond to to_ary but they wouldn't be arrays, but what a hell, it'd respond to it, isn't it? so Ruby would treat the instances of our class as if they were arrays because Ruby would be able to get an array representation of them.
Doesn't all this sounds like duck typing?
Let's summarize.
to_a is used to explicitly convert any object to an array.
to_ary is used to implicitly convert any object to an array or to treat objects as arrays.
oh, yeah, well, but what does to_a and to_ary has to do with the splat operator?
The splat operator is often called the "unary operator", because of "unar[ra]y" (unarray), so, at a first glance it'd seem like to_ary and the unary operator are exactly opposite things. Wrong!
In Ruby 1.8 the splat operator will try to invoke to_ary and then try to invoke to_a in the objects you use it. So, if you want your object to be used with the splat operator you have to implement to_ary on it.
In Ruby 1.9 doesn't work like that because the to_a method have been removed. I've read some posts saying there's a to_splat method but it seems it's gone now, I'm using 1.9.2 and it isn't there.If anyone know anything about to_splat, I'd appreciate if you'd let me know.
Let's continue. In order for to_ary to work with the splat operator, it *must* return an array, what if we try to cheat Ruby?
class Baz
def to_ary
"this is an array, I swear"
end
end
my_baz = Baz.new
my_baz.to_ary # => "this is an array, I swear"
If we explicitly send to_ary to "my_baz", Ruby won't complain about it. The problem comes when we do it implicitly.
def bar_method(arg1, arg2, arg3) [arg1, arg2, arg3] end bar_method(*Baz.new) # => Baz#to_ary should return Array (TypeError)
ok, we couldn't cheat Ruby, so let's fix it.
class Baz
attr_accessor :first, :second, :third
def to_ary
[@first, @second, @third]
end
end
my_baz = Baz.new
my_baz.first = 1
my_baz.second = 2
my_baz.third = 3
bar_method(*my_baz) # => [1,2,3]
Without the to_ary method the result would have been:
bar_method(*my_baz) # => wrong number of arguments (1 for 3)
Last but not least, the to_ary method isn't used only by the splat operator, look at the following code:
first, second, third = my_baz first # => 1 second # => 2 third # => 3
Thanks for reading, any comment would be appreciated!