When I'm working on #3871 for creating the macro of getting the superclasses/ancestors of a Type, I found that if I run the code below, that will show the superclass of Reference
is Class
:
class Reference
def self.superclass
{{@type.superclass}}
end
end
puts Reference.superclass #=> Class
But this is mismatched with the API document which tells that Reference
is inherited from Object
And more, if I change the spec of superclass macro into this, it gives me Reference
's supeerclass is Object
!?
it "executes superclass" do
assert_macro("x", "{{x.superclass}}", %(Reference)) do |program|
# original: [TypeNode.new(program.string)] of ASTNode
[TypeNode.new(program.reference)] of ASTNode
end
end
Failures:
1) macro methods type methods executes superclass
Failure/Error: result.should eq(expected)
expected: "Reference"
got: "Object" # <<<<<<<<< got Object now, why?
# spec/spec_helper.cr:269
Version: 0.20.3, 0.20.4, master
It's a bug in the metamodel, right now if you do:
p Object # => Class
There's a bug with Object and its superclass. We never fixed that.
So, Reference's superclass is Object, but it shows as Class.
@asterite Thanks!
btw, why Class == Object
is true
(use the code below), is that means that Object
is completely the same as Class
in Crystal world?
abstract class Object
def self.superclass
{{@type.superclass}}
end
end
Reference == Object #=> false
Reference == Class #=> false
Reference.superclass == Object #=> true
Reference.superclass == Class #=> true
Class == Object #=> true
Object == Class #=> true
Object.crystal_type_id #=> 588
Class.crystal_type_id #=> 588
It's because the meta-model above Reference (so Object, and Class) is broken... once something is broken you can't rely on things working well :-)
I think the problem is in these lines and this, where we the Object's metaclass to be Class. Normally the metalcass of a type Foo is a new type that's called Foo:Class
which you can see when you something like:
class Foo
end
Foo.x # => undefined method 'x' for Foo:Class
Which is a different method than if you do:
class Foo
end
Foo.new.x # => undefined method 'x' for Foo
That's because to solve Foo.x
we solve the type of Foo
, which is the metaclass, so Foo:Class
, and look up methods there (class methods will be there). To solve Foo.new.x
we first solve Foo.new
, so we solve Foo
which is Foo:Class
, and the new
method will return an instance of Foo, which now has type Foo
, and we search the methodx
in that type.
Now, in program.cr
we set Object's metaclass to Class. So if you have Object
in your program, as an expression, we first solve its type, which is the metaclass, so Class
... and that's kind of wrong. But @waj wanted to model it like that after Objective-C (picture here, you can see Foo's class is called "Foo's metaclass", which in our case would be Foo:Class
, but for NSObject
it's NSObject's metaclass
whose class is itself, so it's like it's also Class
, but that doesn't seem right to me, we need Object:Class
and Class
to be different things), I never really understood why and that probably should be changed. I guess we should have something like Object:Class
and the class of that would be Class
. In fact, I'll change it right away so we can move on with this :-)
Great explanation. Thanks @asterite 馃憤
I changed the title that may be easily searched on GitHub :heart:
To be a bit more clear about the object, the type of a thing like Foo
is to go to the metaclass. In the case of Object
it was Class
, and in the case of Class
it's also Class
, hence their type was the same. I'll change it so that the type of Object
is now Object:Class
.
Fixed! Now in master:
abstract class Object
def self.superclass
{{@type.superclass}}
end
end
Reference == Object # => false
Reference == Class # => false
Reference.superclass == Object # => true
Reference.superclass == Class # => false
Class == Object # => false
Object == Class # => false
Object.crystal_type_id # => 418
Class.crystal_type_id # => 1027
Is that moving towards having Object
be a useable type?
No, that's a completely different issue :-)
Most helpful comment
Fixed! Now in master: