# Case and class

**URL:** <https://www.ruby-forum.com/t/case-and-class/193648>\
**Category:** Ruby\
**Created:** [August 21, 2010, 12:17am UTC](https://www.ruby-forum.com/t/case-and-class/193648 "2010-08-21T00:17:03Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![ralphshnelvar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/e19adc/32.png) [@ralphshnelvar](https://www.ruby-forum.com/u/ralphshnelvar)\
**Post date:** [August 21, 2010, 12:17am UTC](https://www.ruby-forum.com/t/case-and-class/193648/1 "2010-08-21T00:17:03Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![ralphshnelvar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/e19adc/32.png) [@ralphshnelvar](https://www.ruby-forum.com/u/ralphshnelvar)\
**Post date:** [August 21, 2010, 12:39am UTC](https://www.ruby-forum.com/t/case-and-class/193648/2 "2010-08-21T00:39:53Z")

</div>

On Fri, Aug 20, 2010 at 10:51 PM, Ralph S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> 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

---

<div class="post-metadata">

**Author:** ![ralphshnelvar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/e19adc/32.png) [@ralphshnelvar](https://www.ruby-forum.com/u/ralphshnelvar)\
**Post date:** [August 21, 2010, 1:13am UTC](https://www.ruby-forum.com/t/case-and-class/193648/3 "2010-08-21T01:13:52Z")

</div>

Colin,

Friday, August 20, 2010, 4:29:37 PM, you wrote:

CB\> On Fri, Aug 20, 2010 at 10:51 PM, Ralph S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
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

CB\> It’s because of the definition of “===” which is used in the case  
statement.  
CB\> Does the following help?

CB\> class XXX  
CB\> end

CB\> x = XXX.new

CB\> case x.class  
CB\> when XXX then puts “XXX”  
CB\> else puts “YYY” # surprise!  
end #=\>\> YYY

CB\> case x  
CB\> when XXX then puts “XXX 2”  
CB\> else puts “YYY 2”  
end #=\>\> XXX 2

CB\> case x.class  
CB\> when Class then puts “XXX 3”  
CB\> 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 T.’ _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.

---

<div class="post-metadata">

**Author:** ![ralphshnelvar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/e19adc/32.png) [@ralphshnelvar](https://www.ruby-forum.com/u/ralphshnelvar)\
**Post date:** [August 21, 2010, 4:11am UTC](https://www.ruby-forum.com/t/case-and-class/193648/4 "2010-08-21T04:11:11Z")

</div>

On Sat, Aug 21, 2010 at 12:13 AM, Ralph S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> Having read your explanation and Dave T.’ _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

[http://ruby-doc.org/docs/ProgrammingRuby/html/tut\_expressions.html](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.

1. [class Object - RDoc Documentation](http://www.ruby-doc.org/core/classes/Object.html#M000345)  
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.

2. [class Module - RDoc Documentation](http://www.ruby-doc.org/core/classes/Module.html#M001666)  
(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

---

<div class="post-metadata">

**Author:** ![ralphshnelvar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/e19adc/32.png) [@ralphshnelvar](https://www.ruby-forum.com/u/ralphshnelvar)\
**Post date:** [August 22, 2010, 9:53pm UTC](https://www.ruby-forum.com/t/case-and-class/193648/5 "2010-08-22T21:53:38Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![ralphshnelvar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/e19adc/32.png) [@ralphshnelvar](https://www.ruby-forum.com/u/ralphshnelvar)\
**Post date:** [August 21, 2010, 6:10am UTC](https://www.ruby-forum.com/t/case-and-class/193648/6 "2010-08-21T06:10:00Z")

</div>

Colin,

Friday, August 20, 2010, 8:05:36 PM, you wrote:

CB\> On Sat, Aug 21, 2010 at 12:13 AM, Ralph S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> > Having read your explanation and Dave T.’ _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?

CB\> No (I think the following is right, but I’d welcome any corrections)

- case  
CB\> always uses “===”, it’s just that the meaning of “===” may be  
different to  
CB\> “==”.

CB\> 1. case always uses “===” for comparisons; in  
CB\> case x  
CB\> when y then  
CB\> the test is y === x

CB\> [Programming Ruby: The Pragmatic Programmer's Guide](http://ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html)

CB\> Common comparison operators, Operator Meaning  
CB\> == Test for equal value.  
CB\> === Used to test equality within a when clause of a case statement.

CB\> case operates by comparing the target (the expression after the  
keyword  
CB\> case) with each of the comparison expressions after the when  
keywords. This  
CB\> test is done using comparison === target. As long as a class defines  
CB\> meaningful semantics for === (and all the built-in classes do),  
objects of  
CB\> that class can be used in case expressions.  
CB\> …  
CB\> Ruby classes are instances of class Class, which defines === as a  
test to  
CB\> see if the argument is an instance of the class or one of its  
superclasses.

CB\> 2. [class Object - RDoc Documentation](http://www.ruby-doc.org/core/classes/Object.html#M000345)  
obj === other =\>\> true or false  
CB\> Case Equalityâ€”For class Object, effectively the same as calling #==,  
but  
CB\> typically overridden by descendents to provide meaningful semantics  
in case  
CB\> statements.

CB\> 3. [class Module - RDoc Documentation](http://www.ruby-doc.org/core/classes/Module.html#M001666)  
CB\> (remembering that Class is a subclass of Module, which I forget when  
I  
CB\> initially couldn’t find the “===” method in Class)  
mod === obj =\>\> true or false  
CB\> Case Equalityâ€”Returns true if anObject is an instance of mod or one  
of modâ€˜s  
CB\> descendents. Of limited use for modules, but can be used in case  
statements  
CB\> to classify objects by class.

CB\> Putting that all together, and using the String class as an example:  
CB\> x = “Karel Capek”  
CB\> 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 “==”  
CB\> # at least for comparing String objects with String  
objects

p x == String #=\>\> false  
p x === String #=\>\> false

CB\> p x.class == String #=\> true  
CB\> p String == String #=\> true  
CB\> p x.class === String #=\> false  
CB\> p String === String #=\> false

p String == x #=\>\> false  
p String === x #=\>\> true; this is what is being used in the case  
statement  
CB\> # case x; when String then true; else false; end  
CB\> p String == x.class #=\> true  
CB\> 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.

---

<div class="post-metadata">

**Author:** ![ralphshnelvar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/e19adc/32.png) [@ralphshnelvar](https://www.ruby-forum.com/u/ralphshnelvar)\
**Post date:** [August 23, 2010, 1:15am UTC](https://www.ruby-forum.com/t/case-and-class/193648/7 "2010-08-23T01:15:47Z")

</div>

Hi –

On Sat, 21 Aug 2010, Ralph S. wrote:

> 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.

David

–  
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](http://www.compleatrubyist.com)

---

<div class="post-metadata">

**Author:** ![ralphshnelvar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/e19adc/32.png) [@ralphshnelvar](https://www.ruby-forum.com/u/ralphshnelvar)\
**Post date:** [August 23, 2010, 1:52am UTC](https://www.ruby-forum.com/t/case-and-class/193648/8 "2010-08-23T01:52:40Z")

</div>

David,

Sunday, August 22, 2010, 5:15:16 PM, you wrote:

DAB\> Hi –

DAB\> On Sat, 21 Aug 2010, Ralph S. wrote:

> > 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.

DAB\> It doesn’t suggest the same functionality, though. This:

DAB\> case obj  
DAB\> when XXX

DAB\> runs XXX === obj (as per Colin’s explanation), and that examines  
whether  
DAB\> or not XXX is in the method look-up path of obj. This may or may  
not  
DAB\> have anything to do with obj’s class – for example:

DAB\> \>\> class C; end  
DAB\> =\> nil  
DAB\> \>\> module M; end  
DAB\> =\> nil  
DAB\> \>\> c = C.new.extend(M)  
DAB\> =\> #\<C:0x14cd14\>  
DAB\> \>\> case c  
DAB\> \>\> when M; 1  
DAB\> \>\> end  
DAB\> =\> 1

DAB\> If you want to know whether a given class has a certain ancestor,  
you  
DAB\> can do that too, but with a different technique:

DAB\> if C.ancestors.include?(B)

DAB\> etc.

DAB\> In general, the === mechanism is advantageous because it means you  
DAB\> always know what’s going on in a case statement, and because it  
gives  
DAB\> 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.

DAB\> David

Maybe when I understand Ruby a lot better than I do that the explanation  
you provided will make more sense.

---

<div class="post-metadata">

**Author:** ![ralphshnelvar](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/e19adc/32.png) [@ralphshnelvar](https://www.ruby-forum.com/u/ralphshnelvar)\
**Post date:** [August 24, 2010, 12:12am UTC](https://www.ruby-forum.com/t/case-and-class/193648/9 "2010-08-24T00:12:11Z")

</div>

Hi –

On Mon, 23 Aug 2010, Ralph S. wrote:

> DAB\> =\> nil  
> 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

–  
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](http://www.compleatrubyist.com)
