Hi,
The following is a toy abstract from an app I’m writing.
hash = {:Name=>“Tom”}
hash.each_key { |key|
puts “key %s (class = %s) => %s (class = %s)” %
[key.inspect, key.class, hash[key], hash[key].class]
case hash[key].class
when String; p has[key]
else; puts “hash[key].class not found”
end
}
The output is:
key :Name (class = Symbol) => Tom (class = String)
hash[key].class not found
Why isn’t the “when String” statement executed?
Thanks in Advance,
Richard
P.S. I wonder if the time will come when I won’t regularly stumble
over apparent anomalies when writing Ruby code.
user@host:/path$ irb
irb(main):001:0> a = “Foo”
=> “Foo”
irb(main):002:0> a.class === String
=> false
irb(main):003:0> a === String
=> false
irb(main):004:0> a.class === String.class
=> false
irb(main):005:0> a
=> “Foo”
irb(main):006:0> a.inspect
=> ““Foo””
irb(main):007:0> String.inspect
=> “String”
irb(main):008:0> case a
irb(main):009:1> when String
irb(main):010:1> puts ‘string’
irb(main):011:1> else
irb(main):012:1* puts ‘not’
irb(main):013:1> end
string
=> nil
irb(main):014:0> String === a
=> true
irb(main):015:0> a === String
=> false
irb(main):016:0> root@secure:/usr/ports# irb
irb(main):001:0> str = “a string”
=> “a string”
irb(main):002:0> str.class
=> String
irb(main):003:0> String === str.class
=> false
irb(main):004:0> String === str
=> true
irb(main):005:0> case str.class
irb(main):006:1> when String
irb(main):007:1> puts ‘it is a string’
irb(main):008:1> else
irb(main):009:1* puts ‘else executed’
irb(main):010:1> end
else executed
=> nil
irb(main):011:0> case str
irb(main):012:1> when String
irb(main):013:1> puts ‘it is a string’
irb(main):014:1> else
irb(main):015:1* puts ‘else executed’
irb(main):016:1> end
it is a string
=> nil
irb(main):017:0>
Why isn’t the “when String” statement executed?
I believe case/when uses the when object’s === method for matching,
and as you can see from the above irb session, String === “a
string”.class evaluates to false. Hence your code doesn’t work like
you expected.
However, if you change to hash[key] instead of hash[key].class, a
direct comparison to the class object should work (note the String ===
“a string” evaluates to true).
Note that “a string” === String evaluates to false even though “a
string” === String evaluates to true. That way case String when “a
string” won’t match but case “a string” when String will. (Which
totally makes sense in the context of case/when.)
I’m sure I read a great blog post or discussion on this very thing in
the past on the web, one that explains the gory details about exactly
why case/when was designed to work this way. It currently slips my
mind.
Anyone got a good URL for an article/post like that?
Aaron out.
On Jan 26, 7:10pm, “Aaron D. Gifford” [email protected] wrote:
=> “Foo”
string
irb(main):003:0> String === str.class
=> nil
Why isn’t the “when String” statement executed?
Note that “a string” === String evaluates to false even though "a
Aaron out.
Hey Aaron,
You scored a triple. I should say you scored 3 homers. In order of
importance on my grading scale:
-
You solved my problem: Lose the “.class”
-
You showed me that using IRB for experimenting like this is far
better than littering one’s code with debugging statements.
-
You reminded me to RTFM! Actually, I rotate between books, PDFs
and blogs on Ruby, Rails, CSS, RSpec, etc. all the time. But as I
encountered this unfathomable situation, I didn’t do what I’ve now
done: Consult PickAxe (2nd ed., 2005), which confirmed your belief
that case uses === for a comparison of the case parameter and when
arguments.
Many thanks for your deep and insightful solution to my question.
Best wishes,
Richard