Equality of constants

L

Luke A. Kanies

If I run the following code:

if Hash === Hash
puts "yup"
end

I get no output. From what I can tell, this means that I can't test
constants in a when statement. I need something like the following:

array.each { |member|
case member.class
when Object::Subclass
next
end
stuff
}

and if I can't test the equality of constants with === (which is what
'when' uses; why is it a separate operator?), then I can't use them as
values in a when statement. How do I do this?

Thanks,
Luke
 
A

Alex McHale

The answer this doesn't work as you expect is that Class is a subclass
of Module. If you look in the Module definitions, you will see that
for Module === is overridden to mean:

mod === anObject -> 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.

The reason for this different behavior is mentioned in the definition
above -- case statements. It lets you do this sort of thing:

irb(main):020:0> def what_am_i(obj)
irb(main):021:1> case obj
irb(main):022:2> when String
irb(main):023:2> puts "string"
irb(main):024:2> when Hash
irb(main):025:2> puts "hash"
irb(main):026:2> else
irb(main):027:2* puts "somethin else"
irb(main):028:2> end
irb(main):029:1> end
nil
irb(main):030:0> what_am_i []
somethin else
nil
irb(main):031:0> what_am_i "ok"
string
nil

Now if you're bound and determined to do what you want to do, and I
don't know what the repurcussions of this would be, you could override
the === method in Module to use == instead of ===. I just get the
feeling that there would be bad consequences to this.
 
D

David A. Black

Hi --

If I run the following code:

if Hash === Hash
puts "yup"
end

I get no output. From what I can tell, this means that I can't test
constants in a when statement. I need something like the following:

array.each { |member|
case member.class
when Object::Subclass
next
end
stuff
}

and if I can't test the equality of constants with === (which is what
'when' uses; why is it a separate operator?), then I can't use them as
values in a when statement. How do I do this?

=== is separate because it's actually the case operator, not an
equality operator. Actually it's a method; you can define it for your
own classes, to get them to behave how you wish in case statements.

Class#=== is defined to test whether something has the given class
among its ancestors:

case ""
when Fixnum then puts "number?!"
when String then puts "string!"
else puts "mystery"
end

# => string!

(It's kind of weird-looking when used on its own:

String === "" # true

but it's mainly designed with case statements in mind.)

Since Hash is not an instance of Hash, but rather of Class, you're
getting false. Compare with:

Class === Hash # true

So... what you really want to do is:

array.each { |member|
case member # not member.class
when Object::Subclass

etc.


David
 
A

Alex McHale

Dang .. why didn't I think of that. Silly me, it's so obvious.. and I
got so close to that punch line, and managed to totally miss it.
 
D

David A. Black

Hi --

So... what you really want to do is:

array.each { |member|
case member # not member.class
when Object::Subclass

etc.

I realize actually that this isn't identical to what you wanted to do,
since my code will return true for things that are instances of some
subclass of Object::Subclass. If that's OK, then the above is OK. If
not, it's possible that you might be better off with an if statement
than a case statement.

Another thing you could do... Since each Class object (such as
Object::Subclass) is the only instance of its own singleton class,
you could do:

case member.class
when Object::Subclass.singleton_class # true if and only if
# member.class is
# Object::Subclass

Oh, whoops, Kernel#singleton_class doesn't exist :) Here:

module Kernel
def singleton_class
class << self; self; end
end
end


David
 
G

Guillaume Marcais

Le 1 juin 04, à 23:44, Luke A. Kanies a écrit :
If I run the following code:

if Hash === Hash
puts "yup"
end

irb(main):001:0> Hash == Hash
=> true
irb(main):002:0> Hash === {}
=> true

== tests the equality of two object. The fact that they are referred to
by constant is irrelevant:

irb(main):001:0> h = Hash
=> Hash
irb(main):002:0> h == {}.class
=> true

The === operator is used with the case .. when construct and it is a
cool idea. For a module (or class), it is equivalent to kind_of?: Hash
=== {} is equivalent to {}.kind_of?({}).

See the pickaxe.

Guillaume.
 
D

David A. Black

Hi --

Dang .. why didn't I think of that. Silly me, it's so obvious.. and I
got so close to that punch line, and managed to totally miss it.

Don't feel bad -- I had to amend my comments because it's actually not
an exact drop-in replacement for what Luke wanted (see my followup to
myself), though it may well serve his purposes.


David

P.S. Grooving on the functioning gateway!
 
L

Luke A. Kanies

So... what you really want to do is:

array.each { |member|
case member # not member.class
when Object::Subclass

This is exactly sufficient for my needs; all of the objects I am testing
are instances of a subclass of a single parent class, e.g., Nagios::Host,
Nagios::Hostgroup, and Nagios::Command. Thus, I don't have to worry about
parentage or anything.

And thanks for the explanation. A bit strange, but I assume I'll get used
to it.

Luke

--
ACHTUNG!!!

Das machine is nicht fur gefingerpoken und mittengrabben. Ist easy
schnappen der springenwerk, blowenfusen und corkenpoppen mit
spitzensparken. Ist nicht fur gewerken by das dummkopfen. Das
rubbernecken sightseeren keepen hands in das pockets. Relaxen und
vatch das blinkenlights!!!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,146
Messages
2,570,832
Members
47,374
Latest member
anuragag27

Latest Threads

Top