language icon indicating copy to clipboard operation
language copied to clipboard

Small bug in the definition of "instance {methods, getters, setters} of a class"

Open kmillikin opened this issue 9 years ago • 7 comments

@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.

kmillikin avatar Feb 23 '16 14:02 kmillikin

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 avatar Feb 23 '16 18:02 lrhn

@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.

kmillikin avatar Feb 24 '16 08:02 kmillikin

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.

lrhn avatar Feb 24 '16 10:02 lrhn

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.

kmillikin avatar Feb 24 '16 10:02 kmillikin

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.

lrhn avatar Feb 24 '16 12:02 lrhn

No milestone now: This is independent of Dart 2.

eernstg avatar Feb 06 '18 16:02 eernstg

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.

eernstg avatar Nov 13 '19 18:11 eernstg