Why does "YYY" get printed out here?
- - -
class XXX
end
x = XXX.new
case x.class
when XXX
puts "XXX"
else
puts "YYY" # surprise!
end
Why does "YYY" get printed out here?
- - -
class XXX
end
x = XXX.new
case x.class
when XXX
puts "XXX"
else
puts "YYY" # surprise!
end
It's because of the definition of "===" which is used in the case statement.
Does the following help?
class XXX
end
x = XXX.new
case x.class
when XXX then puts "XXX"
else puts "YYY" # surprise!
end #=> YYY
case x
when XXX then puts "XXX 2"
else puts "YYY 2"
end #=> XXX 2
case x.class
when Class then puts "XXX 3"
else puts "YYY 3"
end #=> XXX 3
On Fri, Aug 20, 2010 at 10:51 PM, Ralph Shnelvar <ralphs@dos32.com> wrote:
Why does "YYY" get printed out here?
- - -
class XXX
endx = XXX.new
case x.class
when XXX
puts "XXX"
else
puts "YYY" # surprise!
end
Colin,
Friday, August 20, 2010, 4:29:37 PM, you wrote:
Why does "YYY" get printed out here?
- - -
class XXX
end
x = XXX.new
case x.class
when XXX
puts "XXX"
else
puts "YYY" # surprise!
end
It's because of the definition of "===" which is used in the case statement.
Does the following help?
class XXX
end
x = XXX.new
case x.class
when XXX then puts "XXX"
else puts "YYY" # surprise!
end #=>> YYY
case x
when XXX then puts "XXX 2"
else puts "YYY 2"
end #=>> XXX 2
case x.class
when Class then puts "XXX 3"
else puts "YYY 3"
end #=>> XXX 3
Colin, thank you. Very clear.
Now it's my turn to complain about the unexpected behavior.
Having read your explanation and Dave Thomas' *Programming Ruby 1.9* book about the use of === in comparisons in case statements ...
Is it he fact that *case* uses == (two ='s) for non-Class *when's* and uses === (three ='s) for *when's* that are Classes?
It just seems to me to be an unnecessary surprise to do things differently for objects of class Class.
Indeed
x.class == XXX # => true
X.class _is_ XXX .... and yet the *when* does not pick it up because === is being used for comparison.
Anyway, thank for your lucid and well-written response.
On Fri, Aug 20, 2010 at 10:51 PM, Ralph Shnelvar <ralphs@dos32.com> wrote:
No (I think the following is right, but I'd welcome any corrections) - case
always uses "===", it's just that the meaning of "===" may be different to
"==".
1. case always uses "===" for comparisons; in
case x
when y then
the test is y === x
http://ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html
Common comparison operators, Operator Meaning
== Test for equal value.
=== Used to test equality within a when clause of a case statement.
case operates by comparing the target (the expression after the keyword
case) with each of the comparison expressions after the when keywords. This
test is done using comparison === target. As long as a class defines
meaningful semantics for === (and all the built-in classes do), objects of
that class can be used in case expressions.
...
Ruby classes are instances of class Class, which defines === as a test to
see if the argument is an instance of the class or one of its superclasses.
2. class Object - RDoc Documentation
obj === other => true or false
Case Equality—For class Object, effectively the same as calling #==, but
typically overridden by descendents to provide meaningful semantics in case
statements.
3. class Module - RDoc Documentation
(remembering that Class is a subclass of Module, which I forget when I
initially couldn't find the "===" method in Class)
mod === obj => true or false
Case Equality—Returns true if anObject is an instance of mod or one of mod‘s
descendents. Of limited use for modules, but can be used in case statements
to classify objects by class.
Putting that all together, and using the String class as an example:
x = "Karel Capek"
y = "Karel Capek"
p x.object_id #=> 1880688
p y.object_id #=> 1880656, so x & y are different objects
p x == y #=> true
p x === y #=> true, so for String objects "===" is the same as "=="
# at least for comparing String objects with String objects
p x == String #=> false
p x === String #=> false
p x.class == String #=> true
p String == String #=> true
p x.class === String #=> false
p String === String #=> false
p String == x #=> false
p String === x #=> true; this is what is being used in the case statement
# case x; when String then true; else false; end
p String == x.class #=> true
p String === x.class #=> false; same as String === String
On Sat, Aug 21, 2010 at 12:13 AM, Ralph Shnelvar <ralphs@dos32.com> wrote:
Having read your explanation and Dave Thomas' *Programming Ruby 1.9* book
about the use of === in comparisons in case statements ...Is it he fact that *case* uses == (two ='s) for non-Class *when's* and uses
=== (three ='s) for *when's* that are Classes?
Colin,
Friday, August 20, 2010, 8:05:36 PM, you wrote:
Having read your explanation and Dave Thomas' *Programming Ruby 1.9* book
about the use of === in comparisons in case statements ...
Is it he fact that *case* uses == (two ='s) for non-Class *when's* and uses
=== (three ='s) for *when's* that are Classes?
No (I think the following is right, but I'd welcome any corrections) - case
always uses "===", it's just that the meaning of "===" may be different to
"==".
1. case always uses "===" for comparisons; in
case x
when y then
the test is y === x
Common comparison operators, Operator Meaning
== Test for equal value.
=== Used to test equality within a when clause of a case statement.
case operates by comparing the target (the expression after the keyword
case) with each of the comparison expressions after the when keywords. This
test is done using comparison === target. As long as a class defines
meaningful semantics for === (and all the built-in classes do), objects of
that class can be used in case expressions.
...
Ruby classes are instances of class Class, which defines === as a test to
see if the argument is an instance of the class or one of its superclasses.
obj === other =>> true or false
Case Equality—For class Object, effectively the same as calling #==, but
typically overridden by descendents to provide meaningful semantics in case
statements.
3. class Module - RDoc Documentation
(remembering that Class is a subclass of Module, which I forget when I
initially couldn't find the "===" method in Class)
mod === obj =>> true or false
Case Equality—Returns true if anObject is an instance of mod or one of mod‘s
descendents. Of limited use for modules, but can be used in case statements
to classify objects by class.
Putting that all together, and using the String class as an example:
x = "Karel Capek"
y = "Karel Capek"
p x.object_id #=>> 1880688
p y.object_id #=>> 1880656, so x & y are different objects
p x == y #=>> true
p x === y #=>> true, so for String objects "===" is the same as "=="
# at least for comparing String objects with String objects
p x == String #=>> false
p x === String #=>> false
p x.class == String #=> true
p String == String #=> true
p x.class === String #=> false
p String === String #=> false
p String == x #=>> false
p String === x #=>> true; this is what is being used in the case statement
# case x; when String then true; else false; end
p String == x.class #=> true
p String === x.class #=> false; same as String === String
What a great answer. And, again, clear.
I can, reluctantly, see the use of === in an if statement.
To me,
case x
when XXX then ...
end
would be MUCH clearer as
case x.class
when XXX.arrayOfDecendants
end
Of course, the code above is illegal ... but would have been clearer ... at least to me.
On Sat, Aug 21, 2010 at 12:13 AM, Ralph Shnelvar <ralphs@dos32.com> wrote:
I think of === as meaning 'matches' rather than 'equals'. This is
especially useful as in
case str
when /^foo/
... do something
when /^bar/
... something else
end
For classes, you have
case obj
when String
...
when Integer
...
end
--
Posted via http://www.ruby-forum.com/.
Hi --
I can, reluctantly, see the use of === in an if statement.
To me,
case x
when XXX then ...
endwould be MUCH clearer as
case x.class
when XXX.arrayOfDecendants
endOf course, the code above is illegal ... but would have been clearer ... at least to me.
It doesn't suggest the same functionality, though. This:
case obj
when XXX
runs XXX === obj (as per Colin's explanation), and that examines whether
or not XXX is in the method look-up path of obj. This may or may not
have anything to do with obj's class -- for example:
>> class C; end
=> nil
>> module M; end
=> nil
>> c = C.new.extend(M)
=> #<C:0x14cd14>
>> case c
>> when M; 1
>> end
=> 1
If you want to know whether a given class has a certain ancestor, you
can do that too, but with a different technique:
if C.ancestors.include?(B)
etc.
In general, the === mechanism is advantageous because it means you
always know what's going on in a case statement, and because it gives
you control over how your own objects behave in case statements.
David
On Sat, 21 Aug 2010, Ralph Shnelvar wrote:
--
David A. Black, Senior Developer, Cyrus Innovation Inc.
The Ruby training with Black/Brown/McAnally
Compleat Philadelphia, PA, October 1-2, 2010
Rubyist http://www.compleatrubyist.com
David,
Sunday, August 22, 2010, 5:15:16 PM, you wrote:
Hi --
I can, reluctantly, see the use of === in an if statement.
To me,
case x
when XXX then ...
end
would be MUCH clearer as
case x.class
when XXX.arrayOfDecendants
end
Of course, the code above is illegal ... but would have been clearer ... at least to me.
It doesn't suggest the same functionality, though. This:
case obj
when XXX
runs XXX === obj (as per Colin's explanation), and that examines whether
or not XXX is in the method look-up path of obj. This may or may not
have anything to do with obj's class -- for example:
>> class C; end
=> nil
>> module M; end
=> nil
>> c = C.new.extend(M)
=> #<C:0x14cd14>
>> case c
>> when M; 1
>> end
=> 1
If you want to know whether a given class has a certain ancestor, you
can do that too, but with a different technique:
if C.ancestors.include?(B)
etc.
In general, the === mechanism is advantageous because it means you
always know what's going on in a case statement, and because it gives
you control over how your own objects behave in case statements.
Responding to this last paragraph ...
If I were the language designer I'd have two "cases"
(1) case== which would use the normal == semantics
(2) case=== which would use the === semantics.
Again ... at least this would be clearer to ME.
David
Maybe when I understand Ruby a lot better than I do that the explanation you provided will make more sense.
On Sat, 21 Aug 2010, Ralph Shnelvar wrote:
Hi --
> It doesn't suggest the same functionality, though. This:
> case obj
> when XXX> runs XXX === obj (as per Colin's explanation), and that examines whether
> or not XXX is in the method look-up path of obj. This may or may not
> have anything to do with obj's class -- for example:> >> class C; end
> => nil
> >> module M; end
> => nil
> >> c = C.new.extend(M)
> => #<C:0x14cd14>
> >> case c
> >> when M; 1
> >> end
> => 1Maybe when I understand Ruby a lot better than I do that the
explanation you provided will make more sense.
Here's some annotation:
Every object has a lookup path, consisting of classes and modules in a
particular order, which it traverses when it's trying to resolve a
method name. If you extend an object with a module (see above), you
insert that module into the lookup path of the object. Any module or
class that's in the lookup path of an object (including, but not limited
to, the object's class and modules included in that class) will match
the object for purposes of case equality.
So what I was getting at in my example is that knowing an object's
class, and even that class's ancestors, doesn't tell you everything that
Module#=== tells you. In the example, the "1" shows that M === c, even
though c's class does not include M.
David
On Mon, 23 Aug 2010, Ralph Shnelvar wrote:
--
David A. Black, Senior Developer, Cyrus Innovation Inc.
The Ruby training with Black/Brown/McAnally
Compleat Philadelphia, PA, October 1-2, 2010
Rubyist http://www.compleatrubyist.com