Class#=== has interesting results

  • Thread starter Charles Comstock
  • Start date
C

Charles Comstock

Why does this happen?

class A
end

A == A #1 => true
A === A #2 => false

a = A.new

a === A #3 => false
a == A #4 => false
A === a #5 => true
A == a #6 => false

1 makes sense, A is an A so therefor it should be true
3 and 4 make sense since instance of A is not A and does not match A
5 and 6 make sense in that A matches a, but A is not an a.

But 2 doesn't make any sense to me, why doesn't an A match another A?
Is this just something that slipped through or is there a specific
reason for this?

Charles Comstock
 
J

Jeff Mitchell

--- Charles Comstock said:
Why does this happen?

class A
end

A == A #1 => true
A === A #2 => false

a = A.new

a === A #3 => false
a == A #4 => false
A === a #5 => true
A == a #6 => false

1 makes sense, A is an A so therefor it should be true
3 and 4 make sense since instance of A is not A and does not match A
5 and 6 make sense in that A matches a, but A is not an a.

But 2 doesn't make any sense to me, why doesn't an A match another A?
Is this just something that slipped through or is there a specific
reason for this?

whatisit = case obj
when Array
"it's an array!"
when Hash
"it's a hash!"
when Septuagenarian
"it's a septuagenarian!"
end

$ ri Module#===
------------------------------------------------------------- Module#===
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.




__________________________________
Do you Yahoo!?
Yahoo! Mail - Helps protect you from nasty viruses.
http://promotions.yahoo.com/new_mail
 
C

Charles Comstock

whatisit = case obj
when Array
"it's an array!"
when Hash
"it's a hash!"
when Septuagenarian
"it's a septuagenarian!"
end

$ ri Module#===
------------------------------------------------------------- Module#===
mod === obj => true or false

Right I was trying to use it in an example almost exactly like that
except that obj was a name of a commandclass.

Ie:
def parse(str)
input = str.chomp.split
comm = CommandFactory[input[0]]

case comm
when StartCommand
comm.new(input[1],input[2..-1])
@mobile = input[1]
when HelpCommand
else
comm.new(@mobile,input[1..-1])
end
end

The idea was for a command factory to return the name of the command,
and instantiate that command with the rest of the string as parameters,
except for a few special case examples which would be checked against in
a case statement. Since StartCommand === StartCommand returns false
this doesn't work. Why you would want == to return true and === to
return false in this case is beyond me. I knew about the example you
gave above, that was what I was trying to emulate except at a step before.

Charles Comstock
 
M

Mauricio Fernández

Why does this happen?

class A
end

A == A #1 => true
A === A #2 => false

But 2 doesn't make any sense to me, why doesn't an A match another A?
Is this just something that slipped through or is there a specific
reason for this?

A is not an instance of A; see the ri info for Module#===.

--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

- long f_ffree; /* free file nodes in fs */
+ long f_ffree; /* freie Dateiknoten im Dateisystem */
-- Seen in a translation
 
J

Jeff Mitchell

--- Charles Comstock said:
whatisit = case obj
when Array
"it's an array!"
when Hash
"it's a hash!"
when Septuagenarian
"it's a septuagenarian!"
end

$ ri Module#===
------------------------------------------------------------- Module#===
mod === obj => true or false

Right I was trying to use it in an example almost exactly like that
except that obj was a name of a commandclass.

Ie:
def parse(str)
input = str.chomp.split
comm = CommandFactory[input[0]]

case comm
when StartCommand
comm.new(input[1],input[2..-1])
@mobile = input[1]
when HelpCommand
else
comm.new(@mobile,input[1..-1])
end
end

The idea was for a command factory to return the name of the command,
and instantiate that command with the rest of the string as parameters,
except for a few special case examples which would be checked against in
a case statement. Since StartCommand === StartCommand returns false
this doesn't work. Why you would want == to return true and === to
return false in this case is beyond me. I knew about the example you
gave above, that was what I was trying to emulate except at a step before.

I'm not sure what you mean. StartCommand is not and instance of
StartCommand or one of its decendants, therefore

StartCommand === StartCommand

returns false. Did you want the case statement behave differently
different when given a class?

Does this help:

case comm.to_s.intern
when :StartCommand
comm.new(input[1],input[2..-1])
@mobile = input[1]
when :HelpCommand
else
comm.new(@mobile,input[1..-1])
end





__________________________________
Do you Yahoo!?
New and Improved Yahoo! Mail - 100MB free storage!
http://promotions.yahoo.com/new_mail
 
N

nobu.nokada

Hi,

At Wed, 7 Jul 2004 17:17:36 +0900,
Charles Comstock wrote in [ruby-talk:105460]:
Ie:
def parse(str)
input = str.chomp.split
comm = CommandFactory[input[0]]
case
when comm == StartCommand
comm.new(input[1],input[2..-1])
@mobile = input[1] when comm == HelpCommand
else
comm.new(@mobile,input[1..-1])
end
end

You just stand on a wrong assumption, case/when/=== don't work
as you imagine.
 
C

Charles Comstock

Mauricio said:
A is not an instance of A; see the ri info for Module#===.

At what point does it cause trouble for it to also return true if the
class matches? Can someone give me an example of why it must match an
instance and couldn't match the exact class? I understand it's only
matching instances of the class, I just don't follow the logic behind
why this is the default. Is there example code that uses this assumption?

Charles Comstock
 
A

Austin Ziegler

At what point does it cause trouble for it to also return true if the
class matches? Can someone give me an example of why it must match an
instance and couldn't match the exact class? I understand it's only
matching instances of the class, I just don't follow the logic behind
why this is the default. Is there example code that uses this assumption?

Class === Array

-austin
 
D

David A. Black

Hi --

At what point does it cause trouble for it to also return true if the
class matches?

At the point where you call it :) It can't do both; there would be no
way to interpret the result:

case s
when String ... # what do you do here? print it? instantiate it?


David
 
C

Charles Comstock

Class === Array

Which works because array is a descendent of class. I understand that. I'm
getting the impression that people aren't following why this doesn't make sense
to me so perhaps I can clarify:

------------------------------------------------------------- Module#===
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.


Why is that this is defined like that and not like this:

Case Equality --- Returns true if anObject is an instance of mod, one of mod's
descendents or _is mod_.

I understand what it matches, that is not the purpose of my line of questions, I
am asking why it doesn't also match itself, and for what reason you would want
to match descendents of x but not x itself. Does anyone have a logical reason
why this is the case?

Charles Comstock
 
C

Charles Comstock

Hi --



At the point where you call it :) It can't do both; there would be no
way to interpret the result:

case s
when String ... # what do you do here? print it? instantiate it?

Sorry perhaps I didn't word my question well. I meant when does it cause a
problem for a class x to match itself? What code fails if A === A results in
true? Why would you ever want to match the descendents and instances of A but
not match A itself.

Charles Comstock
 
D

David A. Black

Hi --

Sorry perhaps I didn't word my question well. I meant when does it cause a
problem for a class x to match itself? What code fails if A === A results in
true? Why would you ever want to match the descendents and instances of A but
not match A itself.

It doesn't match the descendants of A, but rather instances of the
descendants of A:

irb(main):001:0> class A; end; class B < A; end
=> nil
irb(main):002:0> case A
irb(main):003:1> when B: puts "yes" end
=> nil
irb(main):004:0> case B
irb(main):005:1> when A: puts "yes" end
=> nil
irb(main):006:0> case B.new
irb(main):007:1> when A: puts "yes" end
yes

It's really the same test as #is_a? The docs should probably add
an "of":

Returns true if anObject is an instance of mod or of
one of mod's descendents.


David
 
J

Jeff Mitchell

--- "David A. Black said:
Sorry perhaps I didn't word my question well. I meant when does it cause a
problem for a class x to match itself? What code fails if A === A results in
true? Why would you ever want to match the descendents and instances of A but
not match A itself.

It doesn't match the descendants of A, but rather instances of the
descendants of A:
[...]

He is asking why isn't === defined as

class Module
def ===(obj)
obj.is_a?(self) or obj == self
end
end

or maybe

class Module
def ===(obj)
obj.is_a?(self) or obj.ancestors.include?(self)
end
end

Not that I advocate either definition.


__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
 
J

Jeff Mitchell

--- Jeff Mitchell said:
or maybe

class Module
def ===(obj)
obj.is_a?(self) or obj.ancestors.include?(self)
end
end

Er, scratch this definition. obj.is_a?(self) is the same thing
as obj.ancestors.include?(self) AFAIK.




__________________________________
Do you Yahoo!?
Yahoo! Mail - 50x more storage than other providers!
http://promotions.yahoo.com/new_mail
 
D

David A. Black

Hi --

--- "David A. Black said:
Sorry perhaps I didn't word my question well. I meant when does it cause a
problem for a class x to match itself? What code fails if A === A results in
true? Why would you ever want to match the descendents and instances of A but
not match A itself.

It doesn't match the descendants of A, but rather instances of the
descendants of A:
[...]

He is asking why isn't === defined as

Right, but the question becomes less relevant given that the method
doesn't actually match the descendants of A -- so the answer is: you
wouldn't, and it doesn't :)
class Module
def ===(obj)
obj.is_a?(self) or obj == self
end
end

or maybe

class Module
def ===(obj)
obj.is_a?(self) or obj.ancestors.include?(self)
end
end

I think you mean obj.class.ancestors, in which case is_a? should take
care of it -- which means that your second definition is actually how
the method works, I believe.

As for the first, and Charles's question about why it doesn't work
that way: look again at my earlier example:

case s
when String ...

With the "is_a? or ==" implementation, this 'when' clause could mean
either that s is String (the Class object) or that s is "Hi, how are
you?" (a String object). Knowing that something is either String or a
string, but not knowing which, isn't very valuable; it's hard to imagine
a case where you would act on that kind of information.


David
 
A

Aredridel

Why is that this is defined like that and not like this:
Case Equality --- Returns true if anObject is an instance of mod, one of mod's
descendents or _is mod_.

Because then it would match some instances of class Class, instances of
mod and instances of descendants of mod. That's three separate things,
two closely related and a third that's not.

It doesn't match descendants of mod -- it matches instances of
descendants of mod.

I can't think of any use-case where matching instances of Class in
addition to instances of Mod would be useful.
I understand what it matches, that is not the purpose of my line of questions, I
am asking why it doesn't also match itself, and for what reason you would want
to match descendents of x but not x itself. Does anyone have a logical reason
why this is the case?

I think you confuse the kind_of? relation with the equals or "is"
relation.

Class kind_of Class
Class kind_of Object
Object kind_of Object
Class is Class
mod is_a Class
instance kind_of mod
instance kind_of Object

but not

instance kind_of Class
instance is_a Class

Ari
 
P

Pit Capitain

David said:
As for the first, and Charles's question about why it doesn't work
that way: look again at my earlier example:

case s
when String ...

With the "is_a? or ==" implementation, this 'when' clause could mean
either that s is String (the Class object) or that s is "Hi, how are
you?" (a String object). Knowing that something is either String or a
string, but not knowing which, isn't very valuable; it's hard to imagine
a case where you would act on that kind of information.

Ack.

And a question to the OP: why do you want to apply the case statement to classes
instead of to their instances? What should this case statement do (depending on
which class is given)? Maybe we can find an alternative to what you think you need.

Regards,
Pit
 
C

Charles Comstock

I think you mean obj.class.ancestors, in which case is_a? should take
care of it -- which means that your second definition is actually how
the method works, I believe.

As for the first, and Charles's question about why it doesn't work
that way: look again at my earlier example:

case s
when String ...

With the "is_a? or ==" implementation, this 'when' clause could mean
either that s is String (the Class object) or that s is "Hi, how are
you?" (a String object). Knowing that something is either String or a
string, but not knowing which, isn't very valuable; it's hard to imagine
a case where you would act on that kind of information.

I don't think you would generally pass either an instance of string or
String to a case statement like this, so it shouldn't generally matter.
However I think I found a better logical explanation as to why this is
false.

String is a constant name that represents a String, however constants
names that represent String are not strings themselves, so therefor it
doesn't match. Thus if s holds String it is holding a reference to a
constant name and not to a String, so it doesn't match.

Which makes sense, and I can accept that logic. Sorry I guess I wasn't
making myself clear in what I was asking and so alot of your responses
were to the question of what Module#=== is useful for, as opposed to
answering my question which was "why doesn't A === A return true".
Which has now been answered.

So now I revise my question:

Given that A === A logically returns false, is there a good way in a
case statement to check if these things are the same by some other
property? For instance a = A; a.id === A.id returns true, but is
that a logical way to test this? Or is there another way?

Charles Comstock
 
C

Charles Comstock

Ack.
And a question to the OP: why do you want to apply the case statement to
classes instead of to their instances? What should this case statement
do (depending on which class is given)? Maybe we can find an alternative
to what you think you need.

Regards,
Pit
def parse(str)
input = str.chomp.split
comm = CommandFactory[input[0]]

case comm
when StartCommand
comm.new(input[1],input[2..-1])
@mobile = input[1]
when HelpCommand
else
comm.new(@mobile,input[1..-1])
end
end

CommandFactory returns the name of the class so that can instantiate it
later with different arguments. Normally all commands reference who
they are from but the start command and help are different since the
start command defines who it is from, and the help command needs to be
accessable before and after the start command has actually instantiated
a character. I could pass these as parameters later on through a
different function, but this seemed a logical way to do it. I think
this should work:

def parse(str)
input = str.chomp.split
comm = CommandFactory[input[0]]

case comm.id
when StartCommand.id
comm.new(input[1],input[2..-1])
@mobile = input[1]
when HelpCommand.id
else
comm.new(@mobile,input[1..-1])
end
end

Since we are matching id's now which is valid. The command factory part
is actually pretty slick too, there is a Command superclass and whenever
anything derives from it, self.inherited gets called on Command, which
then grabs the singleton instance of CommandFactory and adds the
inherited class name to a hash in CommandFactory. So CommandFactory has
a hash which amoung other things includes {"start" => StartCommand,
"help" => HelpCommand}, so when I parse the commandline I just grab the
needed command right out of the CommandFactory and then instantiate it
with the rest of the commandline parameters.

It's just a stupid mud project I am doing to test out pattern based
software design. When it's finished I'll release it to the community as
example code.

I think id should fix my problem, it just suprised me when it didn't
match the name like I thought it would.

Charles Comstock
 
D

David A. Black

Hi --

I don't think you would generally pass either an instance of string or
String to a case statement like this, so it shouldn't generally matter.

The problem is more fundamental, though: you would be unable to know
why "when String" had returned true, so you'd have to test it further
-- so the case statement would have done you no good. If you're sure
in advance, then having the double behavior isn't necessary; and if
you're not sure, then the double behavior makes the method useless.
However I think I found a better logical explanation as to why this is
false.

String is a constant name that represents a String, however constants
names that represent String are not strings themselves, so therefor it
doesn't match. Thus if s holds String it is holding a reference to a
constant name and not to a String, so it doesn't match.

Which makes sense, and I can accept that logic. Sorry I guess I wasn't
making myself clear in what I was asking and so alot of your responses
were to the question of what Module#=== is useful for, as opposed to
answering my question which was "why doesn't A === A return true".

You were clear; my point was that if A === A is true, and A === A.new
is also true, the === method isn't giving you any useful information,
which in turn is a reason for its not being designed that way. As for
the design choice between the two, my impression has always been that
Matz felt the #is_a? one would be more likely to be useful than the
#== one.
Which has now been answered.

So now I revise my question:

Given that A === A logically returns false, is there a good way in a
case statement to check if these things are the same by some other
property? For instance a = A; a.id === A.id returns true, but is
that a logical way to test this? Or is there another way?

id should achieve what you want, or maybe you could use an if
statement instead of a case statment.


David
 

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

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top