Bug #6020

Unexpected is_a/kind_of behaviour

Added by Alex N about 2 years ago. Updated about 2 years ago.

[ruby-core:42607]
Status:Rejected
Priority:Low
Assignee:-
Category:core
Target version:-
ruby -v:ruby 2.0.0dev (2012-02-14 trunk 34598) [x86_64-darwin11.3.0] Backport:

Description

=begin
I've noticed some inconsistent isa?/kindof? methods behavior in a very special cases
self.class #=> Object

BasicObject.isa?(BasicObject) #=> true
Module.is
a?(Module) #=> true
Class.isa?(Class) #=> true
Object.is
a?(Object) #=> true

BasicObject.is_a?(Module) #=> true

Integer.isa?(Integer) #=> false
class A; end
A.is
a?(A) #=> false

module B; end
B.is_a?(B) #=> false

class C < Object; end
C.isa?(C) #=> false
C.is
a?(Object) #=> true
C.isa?(BasicObject) #=> true
C.is
a?(Module) #=> true
C.is_a?(Class) #=> true

c = C.new
c.isa?(Module) #=> false
c.is
a?(Class) #=> false

It looks like it's because Class, Module, Object and BasicObject have class Class, superclass is set properly.
Anyway all is logical but not expected.
=end

History

#1 Updated by Shyouhei Urabe about 2 years ago

  • Status changed from Open to Feedback

Can you show us your "expected behavior"?

#2 Updated by Alex N about 2 years ago

=begin
well, at least (({Integer.isa?(Integer) #=> true})). I can live with that fact that the (({BasicObject.isa?(Module) #=> true})) bearing in mind that the BasicObject is a Class
=end

#3 Updated by Peter Vandenabeele about 2 years ago

On Tue, Feb 14, 2012 at 11:41 AM, Alex N masterlambaster@gmail.com wrote:

Issue #6020 has been updated by Alex N.

=begin
well, at least (({Integer.is_a?(Integer) #=> true})).

TL;DR : use is_a? on an object of the class, not on the class itself.

Long version:

The confusion is that isa? checks if the _object is of class Integer,
not the Integer class.

So.

$ irb
1.9.3p0 :001 > i = 12
=> 12
1.9.3p0 :002 > i.class
=> Fixnum

i is an object of the Fixnum class.

1.9.3p0 :003 > i.is_a?(Integer)
=> true

yes, the object i is an Integer ...

1.9.3p0 :004 > i.is_a?(Fixnum)
=> true

... and also a Fixnum

1.9.3p0 :005 > Integer.class
=> Class
1.9.3p0 :006 > Integer.is_a?(Integer)
=> false

but the class Integer is not an Integer
(because Class does not inherit from Integer).

1.9.3p0 :007 > Class.ancestors
=> [Class, Module, Object, Wirble::Shortcuts, PP::ObjectMixin, Kernel,
BasicObject]

Class only inherits from Module, Object and BasicObject and mixes in some
additional functionality.

HTH,

Peter

--
*** Available for a new project ***

Peter Vandenabeele
http://twitter.com/peter_v
http://rails.vandenabeele.com
http://coderwall.com/peter_v

#4 Updated by Alex N about 2 years ago

=begin
Yes, i know how instance isa? works. The problem is that the module owns the same functionality as well.
For example:
module A; end
A.class #=> Module
A.is
a?(A) #=> false
A.is_a?(A.class) #=> true

From implementation perspective it's totally ok: Module is not A.
But (({A.ancestors})) is (({[A]})), meanwhile (({Module.ancestors})) it the whole set of the core objects. At the same time module A is an BasicObject.
I'm not saying that it's completely wrong, but it feels confusing. On the other had it's really really edge case.
=end

#5 Updated by Konstantin Haase about 2 years ago

Yes, i know how instance is_a? works.

Apparently not.

def is_a?(module)
  self.class.ancestors.include? module
end

A.is_a? A # false since Module.ancestors == [Module, Object, Kernel, BasicObject]
Module.is_a? Module # true since Module.class == Class and Class.ancestors == [Class, Module, Object, Kernel, BasicObject]
BasicObject.is_a? BasicObject # true since BasicObject.class == Class and Class.ancestors == [Class, Module, Object, Kernel, BasicObject]

Konstantin

On Feb 14, 2012, at 12:23 , Alex N wrote:

Issue #6020 has been updated by Alex N.

=begin
Yes, i know how instance isa? works. The problem is that the module owns the same functionality as well.
For example:
module A; end
A.class #=> Module
A.is
a?(A) #=> false
A.is_a?(A.class) #=> true

From implementation perspective it's totally ok: Module is not A.
But (({A.ancestors})) is (({[A]})), meanwhile (({Module.ancestors})) it the whole set of the core objects. At the same time module A is an BasicObject.
I'm not saying that it's completely wrong, but it feels confusing. On the other had it's really really edge case.
=end


Bug #6020: Unexpected isa/kindof behaviour
https://bugs.ruby-lang.org/issues/6020

Author: Alex N
Status: Feedback
Priority: Low
Assignee:
Category: core
Target version:
ruby -v: ruby 2.0.0dev (2012-02-14 trunk 34598) [x86_64-darwin11.3.0]

=begin
I've noticed some inconsistent isa?/kindof? methods behavior in a very special cases
self.class #=> Object

BasicObject.isa?(BasicObject) #=> true
Module.is
a?(Module) #=> true
Class.isa?(Class) #=> true
Object.is
a?(Object) #=> true

BasicObject.is_a?(Module) #=> true

Integer.isa?(Integer) #=> false
class A; end
A.is
a?(A) #=> false

module B; end
B.is_a?(B) #=> false

class C < Object; end
C.isa?(C) #=> false
C.is
a?(Object) #=> true
C.isa?(BasicObject) #=> true
C.is
a?(Module) #=> true
C.is_a?(Class) #=> true

c = C.new
c.isa?(Module) #=> false
c.is
a?(Class) #=> false

It looks like it's because Class, Module, Object and BasicObject have class Class, superclass is set properly.
Anyway all is logical but not expected.
=end

http://bugs.ruby-lang.org/

#6 Updated by Marc-Andre Lafortune about 2 years ago

  • Status changed from Feedback to Rejected

Rejected as is_a? conforms to its description and what many expect.

Alex: Maybe the behavior you are looking for is given by Module#<=:

Integer <= Integer # => true
BasicObject <= Module   # => false
# etc..

Also available in: Atom PDF