Class C < B < A

Hi, I have this case:

  class A ; end
  class B < A ; end
  class C < B ; end

  a = A.new
  b = B.new
  c = C.new

I look for a way (***) to get the following results:

a)
  a *** A => true
  a *** B => false
  a *** C => false

b)
  b *** A => false (*1)
  b *** B => true
  b *** C => false

c)
  c *** A => false (*2)
  c *** B => true
  c *** C => true

Note that I could use ===, so:
  A === a => true
  A === b => false

but in cases *1 and *2 the result is not what I want:

  A === b => true (I want false)
  A === c => true (I want false)

I could play with a.class.ancestors, but isn't another way?

Thanks a lot.

···

--
Iñaki Baz Castillo <ibc@aliax.net>

Iñaki Baz Castillo wrote:

Hi, I have this case:

  class A ; end
  class B < A ; end
  class C < B ; end

  a = A.new
  b = B.new
  c = C.new

I look for a way (***) to get the following results:

...

#instance_of? works for all cases except:

  c *** B => true

Are you sure you need this to be true?

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Iñaki Baz Castillo wrote:

Hi, I have this case:

  class A ; end
  class B < A ; end
  class C < B ; end

  a = A.new
  b = B.new
  c = C.new

I look for a way (***) to get the following results:

a)
  a *** A => true
  a *** B => false
  a *** C => false

b)
  b *** A => false (*1)
  b *** B => true
  b *** C => false

c)
  c *** A => false (*2)
  c *** B => true
  c *** C => true

(...)

Thanks a lot.

The method #kind_of? gives the results you want.

regards,

Siep

···

--
Posted via http://www.ruby-forum.com/\.

Well, it's kinda hackish but it does give the correct output. Tailor to suit your needs:

class A
   alias :like? :instance_of?
end

class B < A; end

class C < B
   def like?( clazz )
     return true if clazz == B
     super
   end
end

a = A.new
b = B.new
c = C.new

[A, B, C].each do |clazz|
   puts "a.like? #{clazz.name} => #{a.like? clazz}"
end
puts

[A, B, C].each do |clazz|
   puts "b.like? #{clazz.name} => #{b.like? clazz}"
end
puts

[A, B, C].each do |clazz|
   puts "c.like? #{clazz.name} => #{c.like? clazz}"
end

==== OUTPUT ====
a.like? A => true
a.like? B => false
a.like? C => false

b.like? A => false
b.like? B => true
b.like? C => false

c.like? A => false
c.like? B => true
c.like? C => true

Again, I'm not proud of this code -- it works, though, without being too tricky.

Blessings,
TwP

···

On Apr 6, 2009, at 4:12 PM, Iñaki Baz Castillo wrote:

Hi, I have this case:

class A ; end
class B < A ; end
class C < B ; end

a = A.new
b = B.new
c = C.new

I look for a way (***) to get the following results:

a)
a *** A => true
a *** B => false
a *** C => false

b)
b *** A => false (*1)
b *** B => true
b *** C => false

c)
c *** A => false (*2)
c *** B => true
c *** C => true

Note that I could use ===, so:
A === a => true
A === b => false

but in cases *1 and *2 the result is not what I want:

A === b => true (I want false)
A === c => true (I want false)

You need to specify somewhere the root of the inheritance hierarchy
you're interested in. Something like this:

class A
  def like?(klass)
    if klass == A
      self.class == A
    else
      self.class <= klass
    end
  end
end

More generally, this will do what you want (at least, what I think you want :wink:

module RootedClassComparison
  def self.included(other)
    module_eval {
      define_method :like? do |klass|
        if klass == other
          self.class == other
        else
          self.class <= klass
        end
      end
    }
  end
end

class A
  include RootedClassComparison
end
class B < A
end
class C < B
end
class D < C
end

a = A.new
b = B.new
c = C.new
d = D.new

klasses = [A, B, C, D]

# test pinched from Tim's example :slight_smile:
klasses.each do |clazz|
  puts "a.like? #{clazz.name} => #{a.like? clazz}"
end
puts

klasses.each do |clazz|
  puts "b.like? #{clazz.name} => #{b.like? clazz}"
end
puts

klasses.each do |clazz|
  puts "c.like? #{clazz.name} => #{c.like? clazz}"
end
puts

klasses.each do |clazz|
  puts "d.like? #{clazz.name} => #{d.like? clazz}"
end

Output:

a.like? A => true
a.like? B => false
a.like? C => false
a.like? D => false

b.like? A => false
b.like? B => true
b.like? C => false
b.like? D => false

c.like? A => false
c.like? B => true
c.like? C => true
c.like? D => false

d.like? A => false
d.like? B => true
d.like? C => true
d.like? D => true

Regards,
Sean

···

On Mon, Apr 6, 2009 at 11:12 PM, Iñaki Baz Castillo <ibc@aliax.net> wrote:

Hi, I have this case:

class A ; end
class B < A ; end
class C < B ; end

a = A.new
b = B.new
c = C.new

I look for a way (***) to get the following results:

a)
a *** A => true
a *** B => false
a *** C => false

b)
b *** A => false (*1)
b *** B => true
b *** C => false

c)
c *** A => false (*2)
c *** B => true
c *** C => true

Note that I could use ===, so:
A === a => true
A === b => false

but in cases *1 and *2 the result is not what I want:

A === b => true (I want false)
A === c => true (I want false)

I could play with a.class.ancestors, but isn't another way?

Thanks a lot.

Yes. Basically A is String and B is a child of String with various methods,
and C is a more specific class.

But I didn't realize of #instance_of?, I will try with it.

Thanks.

···

El Martes 07 Abril 2009, Joel VanderWerf escribió:

Iñaki Baz Castillo wrote:
> Hi, I have this case:
>
> class A ; end
> class B < A ; end
> class C < B ; end
>
> a = A.new
> b = B.new
> c = C.new
>
>
> I look for a way (***) to get the following results:

...

#instance_of? works for all cases except:
> c *** B => true

Are you sure you need this to be true?

--
Iñaki Baz Castillo <ibc@aliax.net>

Iñaki Baz Castillo wrote:

> a)
> a *** A => true
> a *** B => false
> a *** C => false
>
> b)
> b *** A => false (*1)

b.kind_of? A
=> true

> b *** B => true
> b *** C => false
>
> c)
> c *** A => false (*2)

c.kind_of? A
=> true

> c *** B => true
> c *** C => true

(...)

> Thanks a lot.

The method #kind_of? gives the results you want.

Not in the above cases. It's the same as using === :frowning:

···

El Martes 07 Abril 2009, Siep Korteling escribió:

--
Iñaki Baz Castillo <ibc@aliax.net>

So freak! :slight_smile:

Thanks a lot.

···

El Martes 07 Abril 2009, Tim Pease escribió:

==== OUTPUT ====
a.like? A => true
a.like? B => false
a.like? C => false

b.like? A => false
b.like? B => true
b.like? C => false

c.like? A => false
c.like? B => true
c.like? C => true

Again, I'm not proud of this code -- it works, though, without being
too tricky.

--
Iñaki Baz Castillo <ibc@aliax.net>

Frankly, I find this a bit spooky for several reasons: first, you inherit String which IMHO is almost always a bad idea(tm). You should consider using delegation, so you have

class B
   attr_reader :str
end

class C < B; end

Then, you introduce inconsistencies in inheritance checking. That might yield all sorts of surprises.

If you want to do it nevertheless, I'd probably go for a special method which you override appropriately:

class Module
   def class_of?(obj)
     if self == String
       self == obj.class
     else
       self === obj
     end
   end
end

class B < String
end

class C < B
end

classes = [String,B,C]
classes.each do |cl|
   puts cl
   o = cl.new

   classes.each do |cl2|
     print cl2, " ", cl2.class_of?(o), "\n"
   end

   puts "--"
end

Something along these lines.

Kind regards

  robert

···

On 07.04.2009 00:41, Iñaki Baz Castillo wrote:

El Martes 07 Abril 2009, Joel VanderWerf escribió:

Iñaki Baz Castillo wrote:

Hi, I have this case:

  class A ; end
  class B < A ; end
  class C < B ; end

  a = A.new
  b = B.new
  c = C.new

I look for a way (***) to get the following results:

...

#instance_of? works for all cases except:

  c *** B => true

Are you sure you need this to be true?

Yes. Basically A is String and B is a child of String with various methods, and C is a more specific class.

Thanks a lot. However I've already solved it by changing my classes
definitions so I don't have that painful requeriment anymore :slight_smile:

···

El Martes 07 Abril 2009, Robert Klemme escribió:

Frankly, I find this a bit spooky for several reasons: first, you
inherit String which IMHO is almost always a bad idea(tm). You should
consider using delegation, so you have

--
Iñaki Baz Castillo <ibc@aliax.net>