-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Compiler Internals: Instance Variables
From https://github.com/crystal-lang/crystal/issues/11673#issuecomment-1020368147
- instance variables of modules are just used to compute what instance variables classes and structs will have
- in a hierarchy, an instance variable belongs to the top-most type that defines it
So for instance if we have:
class A
@a = 1
end
class B < A
@b = 1
end
We have that A
holds @a : Int32
and B
holds @b : Int32
. Also B
holds @a : Int32
through A, but that information is kept in A
, not in B.
Let's say we have this:
class A
@a = 1
end
class B < A
@a = 3
@b = 1
end
In this case there's also @a : Int32
, but the end result is the same as before: @a : Int32
belongs to A, B
knows nothing about it directly (it knows about the initializer, though)
To be able to do this the compiler will analyze type hierarchies starting from root types and going downwards.
This... kind of falls apart with modules!
What Crystal does right now is to analyze modules first, before classes and structs. If a module mentions an instance variable, that instance variable is propagated to inherited types.
So in a code like this:
module Moo
@a = 1
end
class Foo
@b = 2
end
- We first process
Moo
, and then we know thatFoo
needs to have@a : Int32
- Then we process
Foo
and learn that it also has@b : Int32
The end result is that Foo
will have:
@a : Int32
@b : Int32
So far, so good.
But with this example
module M
@a = 1
end
abstract class A
@a = 1
end
class B < A
include M
@b = 1
end
B.new
- We first process
M
and we learn thatB
needs to have@a : Int32
- We then process
A
and learn that it needs to have@a : Int32
- We then process
B
and learn that it needs to have@b : Int32