tags:

views:

110

answers:

2

x == User returns true, but case x statement does not run the block associated with User. What's happening here?

u = User.new
# => #<User:0x00000100a1e948>

x = u.class
# => User

x == User
# => true

case x
when User
  puts "constant"
when "User"
  puts "string"
else
  puts "nothing?"
end
# => nothing?
+1  A: 

In case statement , the comparison is done using === operator.

So your code is translated to following:

case x
when User === x 
    puts "Constant"
when "User" === x
    puts "string"
else 
    puts "nothing"
end

Different class define === in different way:

The Class class define === so that it tests whether the righthand operand (x)is an instance of the class named by the lefthand operand (User). So , It is not surprise that User === x will be evaluated as false. Instead, User === u (u = User.new) is true.

irb(main):001:0> class User
irb(main):002:1> end
=> nil
irb(main):003:0> u = User.new
=> #<User:0xb7a90cd8>
irb(main):004:0> User === u.class
=> false
irb(main):005:0> User === u
=> true
pierr
@pierr, I just found out that `User === u` is not the same as `u === User`. This is getting far too confusing...
macek
@macek, `===` is defined by the receiver, `User` is a class and so has a different (and special) definition of `===` to an arbitrary object. Any given object can implement `===` however they want, see: `class << u; def ===(o); puts "hello world and #{o} !!"; end; end` and then: `u === U #=> "hello world and U !!"`
banister
+13  A: 

Case comparisons use === rather than ==. For many objects the behaviour of === and == is the same, see Numeric and String:

5 == 5 #=> true
5 === 5 #=> true

"hello" == "hello" #=> true
"hello" === "hello" #=> true

But for other kinds of object === can mean many things, entirely depending on the receiver.

For the case of classes, === tests whether an object is an instance of that class:

Class === Class.new #=> true. 

For Range it checks whether an object falls in that range:

(5..10) === 6 #=> true

For Procs, === actually invokes that Proc:

multiple_of_10 = proc { |n| (n % 10) == 0 }
multiple_of_10 === 20 #=> true (equivalent to multiple_of_10.call(20))

For other objects, check their definition of === to uncover their behaviour. It's not always obvious, but they usually make some kind of sense..

Here is an example putting it all together:

case number
when 1
    puts "One"
when 2..9
    puts "Between two and nine"
when multiple_of_10
    puts "A multiple of ten"
when String
    puts "Not a number"
end  

See this link for more info: http://www.aimred.com/news/developers/2008/08/14/unlocking_the_power_of_case_equality_proc/

banister
+1: Thanks for insight!
Rekin
@banister, this is all very helpful information, a lot I didn't know, too, but I don't feel like it addresses my confusion. With `a = Foo.new.class` and `b = Foo`, both `a` and `b` are set to `Foo`; also, `a.class` and `b.class` are `Class`. How come `a === b #=> false`? According to docs, `Object#===` is equivalent to `#==` unless overridden. What's going on in my specific case?
macek
@macek, because (as i said) `===` *is* overridden for classes. So `Foo === Foo` will return false as `===` in that context checks `is_a?` and not straight equality.
banister
@macek: `Foo` is an instance of [`Class`](http://www.ruby-doc.org/core/classes/Class.html); `Class` inherits from [`Module`](http://www.ruby-doc.org/core/classes/Module.html). [`Module#===`](http://www.ruby-doc.org/core/classes/Module.html#M001666) (thus `Foo.===`) is where `x === y` is defined to mean “is y an instance of x?”.
Chris Johnsen