Can't case on class?


(Gavin Kistner) #1

The code below produces the following output:

Class is ValidForm::OptionSet.
Is it OK? true
What about this: false
WTF?

1 class ValidForm::Option
2 def field_tohtml(indentLevel=0)
3 puts "Class is #{@optionSet.class}."
4 puts "Is it OK? #{@optionSet.class==ValidForm::OptionSet}"
5 puts "What about this: #{@optionSet==ValidForm::OptionSet}"
6 case @optionSet.class
7 when ValidForm::OptionSet
8 #…
9
10 when ValidForm::CheckboxSet
11 #…
12
13 when ValidForm::RadioSet
14 #…
15
16 else
17 puts 'WTF?'
18 end
19 end
20 end

Thanks to memmove on #ruby-lang I found that if I change line #6 to:

case @optionSet   #no .class here

then it works, but I don’t understand why.

Can someone explain why the former doesn’t work?
If this isn’t an official bug, I call it a design flaw :slight_smile:

···


(-, /\ / / //


(Kent S.) #2

Gavin Kistner wrote:

The code below produces the following output:

Class is ValidForm::OptionSet.
Is it OK? true
What about this: false
WTF?

1 class ValidForm::Option
2 def field_tohtml(indentLevel=0)
3 puts "Class is #{@optionSet.class}."
4 puts "Is it OK? #{@optionSet.class==ValidForm::OptionSet}"
5 puts "What about this: #{@optionSet==ValidForm::OptionSet}"
6 case @optionSet.class
7 when ValidForm::OptionSet
8 #…
9
10 when ValidForm::CheckboxSet
11 #…
12
13 when ValidForm::RadioSet
14 #…
15
16 else
17 puts 'WTF?'
18 end
19 end
20 end

Thanks to memmove on #ruby-lang I found that if I change line #6 to:

case @optionSet #no .class here

then it works, but I don’t understand why.

Can someone explain why the former doesn’t work?
If this isn’t an official bug, I call it a design flaw :slight_smile:

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

/kent


(Gavin Kistner) #3

Kent S. wrote:

Gavin Kistner wrote:

3 puts "Class is #{@optionSet.class}."
4 puts "Is it OK? #{@optionSet.class==ValidForm::OptionSet}"
5 puts "What about this: #{@optionSet==ValidForm::OptionSet}"
6 case @optionSet.class

 mod === obj    => true or false

Bah, I forgot that case used === and not ==. Thanks, Kent.
So the questions I have now are:

a) Why does someClass===someClass return false?

b) Why does the case fooInstance; when FooClass; work?

I ask the second because:

irb(main):001:0> foo = %w{ a b c d }
=> [“a”, “b”, “c”, “d”]
irb(main):002:0> foo.class
=> Array
irb(main):003:0> foo.class==Array
=> true
irb(main):004:0> foo.class===Array
=> false
irb(main):005:0> foo==Array
=> false
irb(main):006:0> foo===Array
=> false

Line 4 confirms what Kent pointed out…but line 6 seems to indicate
that the case statement switching off of the instance itself (which does
work) should not work.

···


(-, /\ / / //


(Gavin Kistner) #4

Gavin Kistner wrote:

irb(main):006:0> foo===Array
=> false

Line 4 confirms what Kent pointed out…but line 6 seems to indicate
that the case statement switching off of the instance itself (which does
work) should not work.

Nevermind, I was confusing the appearance of === as a commutative
operator with the fact that it’s actually a method call.

(foo===Array) != (Array===foo)

and apparently the latter is the order that is used in a case statement.

I can see the reason that Module#=== was thus defined (and the power
that the definition enables)…but the principle of most surprise
strikes again :slight_smile:

···


(-, /\ / / //


(Robert) #5

“Gavin Kistner” gavin@refinery.com schrieb im Newsbeitrag
news:xkbZb.346875$I06.3646685@attbi_s01…

Gavin Kistner wrote:

irb(main):006:0> foo===Array
=> false

Line 4 confirms what Kent pointed out…but line 6 seems to indicate
that the case statement switching off of the instance itself (which
does

work) should not work.

Nevermind, I was confusing the appearance of === as a commutative
operator with the fact that it’s actually a method call.

Btw: == is a method call, too. You can’t define operators independent of
a class in Ruby. All operators that you can define, have to sit in a
class. It’s just the syntax (“a + b”) that mimics independence and
commutability.

(foo===Array) != (Array===foo)

and apparently the latter is the order that is used in a case statement.

I can see the reason that Module#=== was thus defined (and the power
that the definition enables)…but the principle of most surprise
strikes again :slight_smile:

Well, that’s just a normal event during learning: you’re surprised by
something you didn’t know beforehand, investigated and learned something.
Nothing that would indicate that POLS is violated.
:slight_smile:

Kind regards

robert