language
language copied to clipboard
Small bug in the definition of "instance {methods, getters, setters} of a class"
@gbracha Section 10.9.1 Inheritance (3rd edition) defines inheritance of instance members in terms of accessible members of "a superclass" (i.e., the superclass or one of its superclasses) that are not overridden.
The language in Sections 10.1 Instance Methods, 10.2 Getters, and 10.3 Setters use the wording "its superclass", which is probably just left over from an earlier version. For example from 10.1:
The instance methods of a class C are those instance methods declared by C and the instance methods inherited by C from its superclass.
This would seem to disallow instance methods from superclasses of its superclass because elsewhere in the spec the words "its superclass" is always used to refer to "the superclass" of a class.
One fix is to change "inherited by C from its superclass." to "inherited by C from its superclasses." or similar. Another better fix might be to change to "inherited by C." and cross-reference Section 10.9.1 since that's where inheritance is defined.
If you consider the superclass of C to have all the members that it declares or inherits, then there is no need to look further into the superclass chain (well, unless "accessible" somehow gets into the definition so you don't inherit inaccessible members, then you do need to look further).
@lrhn That's the issue. Accessibility is explicit in the definition of inheritance in 10.9.1.
Let C be a class, let A be a superclass of C, and let S1 . . . Sk be superclasses of C that are also subclasses of A. C inherits all accessible instance members of A that have not been overridden by a declaration in C or in at least one of S1 . . . Sk.
And there's a note explaining why:
It would be more attractive to give a purely local definition of inheritance, that depended only on the members of the direct superclass S. However, a class C can inherit a member m that is not a member of its superclass S. This can occur when the member m is private to the library L1 of C, whereas S comes from a different library L2, but the superclass chain of S includes a class declared in L1.
I'm not sure it makes sense to not inherit inaccessible members - depending on what "inherit" means in this context.
If class C
in library L1
has methods foo
and _bar
, with foo
calling _bar
, and class D
in library L2
extends C
, then instances of D
must also have the _bar
method, otherwise everything breaks down.
So, instances of D
definitely have an inherited _bar
method. The only real question is whether the interface of D
has _bar
method.
I'm not entirely decided on what is best. It's probably better if the interface of D
does not have the member that it doesn't know about. That means that even inside C
, the D
interface won't have a _bar
member - which is the only safe assumption because someone can implement D
without a _bar
. (Now assign a D
instance to C
variable, and the fun begins, but that's always been the case!)
So, you definitely inherit the implementation of inaccessible members of your superclass. You (or your interface) probably don't inherit the declaration of inaccessible members (or maybe you do, you just don't get any warnings related to inaccessible members - like them not being implemented, in case your superclass is abstract). It's a mess either way.
I think using the "current library" (defined as the library currently being compiled) in method lookup is intended to take care of that case.
In the implementation of foo
the current library is L1
, so the call to _bar
will be resolved by looking up _bar
in D
with respect to library L1
. That fails according to the definition of inheritance because D
doesn't have a method _bar
. Then the lookup proceeds to the superclass C
with respect to library L1
where it finds an implementation.
So you are saying that "inherit" in this case is only talking about the interface, because the implementation isn't "inherited" at all, but rather "looked up" in the superclass chain?
In that case, I agree that 10.1 and 10.9.1 are inconsistent. I would personally favor the version that only inherits from the superclass, not all superclasses. If a class C
in library L1
has a private member _bar
, and a class D
in library L2
implements C
, then L2
doesn't know about _bar
. If class E
in library L1
then extends D
, it seems spurious to get a warning that E
should be abstract because it doesn't implement _bar
.
No milestone now: This is independent of Dart 2.
One fix is to change "inherited by C from its superclass." to "inherited by C from its superclasses."
This should be done here. Instance variables are covered here, and the text should talk about induced setters/getters rather than about "inheriting" instance variables. Getters need the fix here, and setters here. No further actions planned for this issue.