[swift-evolution] Require use of override keyword to override dynamically dispatched methods defined in a protocol with a default implementation

Xiaodi Wu xiaodi.wu at gmail.com
Wed Jan 6 18:33:12 CST 2016


> I don't like this solution because the compiler produces poor error
> messages. It says that the type that implements the protocol doesn't conform
> to the protocol in all three cases described below. Whereas if override were
> required the compiler would say one of:

I completely agree that the compiler's error messages are currently
vague and unhelpful. I don't have any experience in terms of how the
compiler goes about its job, but it seems to me that it's an
orthogonal issue? Whether `override` is required everywhere or no, if
the compiler has enough information to know that the type is
nonconforming, surely it could be spruced up to know which methods or
properties are missing even while maintaining today's syntax? Someone
who's expert in this could probably chime in here. I get the sense
from this list that the community and core team are not in favor of
changing syntax only to make up for deficiencies in tooling, though
honestly I don't think the syntax would be worse off if we do it your
way.

> I would prefer final to be required so that it is clear that this is a
> static dispatch.

I've tried to follow the other thread about this. I'm not clear that I
fully grasp the proposal but that's my fault. Something isn't clicking
about how final (which I understand in the context of class
hierarchies) works in the context of protocol extensions. Would this
mean that if a protocol extension defines a statically dispatched and
therefore mandatory 'final' method foo() that I'm no longer allowed to
have a method foo() in a conforming class? That seems like it could
make a lot of things blow up especially in the context of retroactive
modeling as discussed above. Perhaps I'm just not understanding.


On Wed, Jan 6, 2016 at 5:56 PM, Howard Lovatt <howard.lovatt at gmail.com> wrote:
> Comments in-line below.
>
>
> On Thursday, 7 January 2016, Xiaodi Wu via swift-evolution
> <swift-evolution at swift.org> wrote:
>>
>> > Another option might be to allow imported definitions to be used by a
>> > conformance without the `override` marking to support retroactive
>> > modeling
>> > while requiring definitions in the same module as the conformance to
>> > explicitly specify the `override`.
>>
>> That's an interesting suggestion. I don't think I'd prefer that
>> solution, though, because I would imagine that it's during retroactive
>> modeling of someone else's stuff that ambiguity regarding what's
>> overridden or not might occur.
>>
>> I've been slow in fully understanding Greg Parker's feedback, but on
>> reflection it may be the only way to satisfy all use cases. In
>> Thorsten's scenario where neither the protocol and its extension nor
>> the type is under the control of the user, making the type conform to
>> the protocol would either require no keyword requirements regarding
>> overriding methods (as it is, and as you suggest) or else a syntax to
>> indicate an overriding method must exist *within the extension that
>> conforms a type to a protocol* (as Greg suggests).
>>
>> Can I propose an amended solution then?
>>
>> (1) When a protocol requires a method (or property getter/setter,
>> etc.) but doesn't provide a default implementation, no keyword is used
>> anywhere since all conforming types must provide their own
>> implementation--I suppose a requirement could be made for a keyword,
>> but I don't know that it adds much in terms of guarding against
>> unintended behavior; I guess that can be a continued point of
>> discussion
>>
>>
> I don't like this solution because the compiler produces poor error
> messages. It says that the type that implements the protocol doesn't conform
> to the protocol in all three cases described below. Whereas if override were
> required the compiler would say one of:
>
> 1. If the method was completely absent or there was a typo and no override
> the compiler could identify the missing method as an error on the type.
> 2. If the method had the same signature as a protocol method but no override
> (or had final) the compiler could say that override is required and
> importantly identify the method at fault
> 3. If the method had override but a typo the compiler could say that it does
> not override a method and importantly identify the method at fault.
> 4. If the method had both final and override the compiler could say that
> both not allowed and importantly identify the method at fault.
>
> Which is much more fine grained and informative.
>>
>>
>> (2) When a protocol doesn't declare a method but an extension to the
>> protocol provides one, types implementing a method with the same
>> signature *must not* declare it to be overriding; such protocol
>> extension methods are not overridden because they can be invoked after
>> upcasting
>>
> I would prefer final to be required so that it is clear that this is a
> static dispatch.
>>
>>
>> (3) When a protocol does declare a method, and an extension to the
>> protocol provides a default implementation, then to override that
>> implementation *either* the implementing type *or* an extension must
>> use the keyword `override`
>>
>> (3a) In the case of an implementing type, `override func` is used
>> instead of `func`, just as in the case of a class overriding a
>> superclass method
>>
>> (3b) In the case of an extension to a type (this is the syntax I could
>> come up with, but maybe it'll be objectionable in other ways), a
>> method in an existing class can be retroactively made overriding by
>> declaring `override [method signature]` with no body, similar to the
>> way that a method is declared inside a protocol; by analogy, an
>> overriding getter might use the syntax
>>
>> extension Int: BoundedType {
>>     static var min { override get }
>> }
>>
>> I think the syntax proposed in (3b) has the virtue of not requiring
>> additional keywords, being sufficiently similar to (3a) so that it's
>> not surprising, but still sufficiently unique in that the syntax is
>> not currently valid code and thus isn't currently used to mean
>> anything else.
>>
>>
>> On Wed, Jan 6, 2016 at 8:21 AM, Matthew Johnson <matthew at anandabits.com>
>> wrote:
>> >
>> > On Jan 6, 2016, at 3:48 AM, Greg Parker via swift-evolution
>> > <swift-evolution at swift.org> wrote:
>> >
>> >
>> > On Jan 5, 2016, at 8:50 PM, Brent Royal-Gordon via swift-evolution
>> > <swift-evolution at swift.org> wrote:
>> >
>> > Taking inspiration from syntax used for methods in classes that override
>> > methods in superclasses, require methods that override dynamically
>> > dispatched default implementations in protocol extensions to use the
>> > override keyword. Likewise, forbid the override keyword if the method
>> > being
>> > implemented instead 'masks' (would that be the right word?) a statically
>> > dispatched method in a protocol extension which can nonetheless be
>> > invoked
>> > by upcasting to the protocol.
>> >
>> >
>> > This has been suggested before, usually in the form of a separate
>> > `implement` keyword. The main problem is that it makes it impossible to
>> > write a protocol after the fact which formalizes some existing pattern
>> > in
>> > the types.
>> >
>> > What do I mean by that? Well, imagine you need generic access to the
>> > `min`
>> > and `max` static properties of the various integer types. There's no
>> > existing protocol that includes those members. But you can write one and
>> > then extend the integer types to conform to your new protocol:
>> >
>> > protocol BoundedIntegerType: IntegerType {
>> > static var min: Self { get }
>> > static var max: Self { get }
>> > }
>> > extension Int: BoundedType {}
>> > extension Int8: BoundedType {}
>> > extension Int16: BoundedType {}
>> > extension Int32: BoundedType {}
>> > extension Int64: BoundedType {}
>> >
>> > func printLowestPossibleValueOfValue<Integer: BoundedIntegerType>(x:
>> > Integer) {
>> > print(Integer.min)
>> > }
>> >
>> > This only works because `min` and `max` *don't* need any special marking
>> > to
>> > be used to satisfy a requirement. Requiring a keyword like you suggest
>> > would
>> > remove that feature.
>> >
>> >
>> > Possible solution: if you want a new protocol adoption to map to some
>> > existing method or property then you must explicitly write that. You
>> > can't
>> > just adopt the protocol in an empty extension.
>> >
>> >    extension Int: BoundedType {
>> >        static var min = Int.min
>> >        static var max = Int.max
>> >    }
>> >
>> > but with some other syntax that isn't ambiguous. Code completion and
>> > compiler fix-its could suggest this when the class already implements
>> > something suitable.
>> >
>> >
>> > Another option might be to allow imported definitions to be used by a
>> > conformance without the `override` marking to support retroactive
>> > modeling
>> > while requiring definitions in the same module as the conformance to
>> > explicitly specify the `override`.
>> >
>> >
>> >
>> > --
>> > Greg Parker     gparker at apple.com     Runtime Wrangler
>> >
>> >
>> > _______________________________________________
>> > swift-evolution mailing list
>> > swift-evolution at swift.org
>> > https://lists.swift.org/mailman/listinfo/swift-evolution
>> >
>> >
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> --
>   -- Howard.
>


More information about the swift-evolution mailing list