Require use of override keyword to override dynamically dispatched methods defined in a protocol with a default implementation


(Xiaodi Wu) #1

Dipping my toes in the water, so to speak, with a suggestion that came to
mind. Not an expert by any means, so hopefully this isn't too laughably off
the mark. As background, I work in the biomedical sciences; with few
exceptions, those of us who write code are non-experts who learn as we go
along. What's been attractive about Swift is that it's been designed with
approachability in mind for beginning coders and those with a rudimentary
understanding of languages in the C family. Difficulty in syntax and
sophistication of the computer science concepts exposed are hurdles that
can be overcome, but what keeps me up at night are potentially subtle
things maybe easy for the expert that I or my colleagues just might not
know about, which then lead to code that appears correct at first glance,
compiles, but executes in subtly unintended ways. Those things in my field
are what could lead to retracted papers, ruined careers, etc....

This is something along those lines; also somewhat of a reprise of a theme
that's been raised tangentially in a few threads within the past month
(e.g.:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001125.html),
but I think the particular solution I'm envisioning hasn't been put forward.

The issue at hand:

Consider the following (contrived) example (call it version 1)--

class Animal {
    func makeNoise() -> String {
        return "generic sound"
    }
}

class Cow: Animal {
    override func makeNoise() -> String {
        return "moo"
    }
}

class Sheep: Animal {
    override func makeNoise() -> String {
        return "bah"
    }
}

let cow = Cow()
cow.makeNoise() // "moo"
(cow as Animal).makeNoise() // "moo"

let farm: [Animal] = [Cow(), Cow(), Sheep()]
let noises: [String] = farm.map { $0.makeNoise() }
// ["moo", "moo", "bah"]

Now refactor to use a protocol. I'll give two versions, differing by a
single line.

Version 2A--

protocol Animal { }

extension Animal {
    func makeNoise() -> String {
        return "generic sound"
    }
}

class Cow: Animal {
    func makeNoise() -> String {
        return "moo"
    }
}

class Sheep: Animal {
    func makeNoise() -> String {
        return "bah"
    }
}

let cow = Cow()
cow.makeNoise() // "moo"
(cow as Animal).makeNoise() // "generic sound"

let farm: [Animal] = [Cow(), Cow(), Sheep()]
let noises: [String] = farm.map { $0.makeNoise() }
// ["generic sound", "generic sound", "generic sound"]

Version 2B--

protocol Animal {
    func makeNoise() -> String
}

extension Animal {
    func makeNoise() -> String {
        return "generic sound"
    }
}

class Cow: Animal {
    func makeNoise() -> String {
        return "moo"
    }
}

class Sheep: Animal {
    func makeNoise() -> String {
        return "bah"
    }
}

let cow = Cow()
cow.makeNoise() // "moo"
(cow as Animal).makeNoise() // "moo"

let farm: [Animal] = [Cow(), Cow(), Sheep()]
let noises: [String] = farm.map { $0.makeNoise() }
// ["moo", "moo", "bah"]

To be sure, this difference in behavior can be justified in a variety of
ways, but it is nonetheless a surprising result at first glance. Most
concerning is that it is possible to imagine a scenario in which the
protocol in question is one provided in a third-party library, or even the
Swift standard library, while I'm writing a struct or class that implements
that protocol.

Suppose that between versions of a third-party library the Animal protocol
changes from version 2A to version 2B. My struct or class that implements
the protocol would compile without changes, and cow.makeNoise() would even
give the same result, yet there would be differences in how my code works
that would be difficult to track down. An expert would be able to spot the
difference on examination of the protocol declaration, but one would have
to be knowledgeable already about this particular issue to know what to
look for. This seems like a gotcha that can be avoided.

Proposed solution:

I think others have tried to approach this from a different angle (see, for
example:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001933.html).
My view is that there are two points potentially to address.

(1) func makeNoise() -> String { ... } within the protocol extension
indicates two different things in versions 2A and 2B (since one is
dynamically dispatched and the other is not), yet the syntax is
indistinguishable.

(2) Within a class or struct implementing a protocol, a method with the
same name as that of a method in a protocol extension (potentially in
another file, maybe not written by the same person) behaves differently
depending on whether that method name is declared in the protocol itself
(potentially in a third file, written by a third person), yet the syntax is
indistinguishable within the implementing class or struct. If the protocol
changes, whether a method is dynamically dispatched or statically
dispatched could change too, yet code in a class or struct implementing
that protocol that now behaves differently compiles all the same;
implementors are not clued into the change and may not even be aware that
changes such as this could happen.

What I'm thinking is a light-touch fix that would address (2), which would
largely mitigate the consequences of (1). 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.

In other words, I propose that in the contrived example above, version 2B
(which behaves just like version 1) requires syntax just like that of
version 1 (in class Cow and class Sheep, override func makeNoise() ->
String { ... }). Meanwhile, version 2A, which doesn't quite behave like
version 1, forbids the same syntax. That way, anyone confused about what he
or she is getting into when implementing the protocol is notified at
compile time, and code that compiles in one scenario will not compile if
the underlying protocol declaration changes.

I suppose quite a good counterargument would be that protocols exist to be
implemented, and implementations of methods required for conformance to a
protocol shouldn't need another keyword. I would be inclined to agree, but
in this case I'd point out that what would trigger the requirement for use
of the override keyword is the presence of a default implementation being
overridden, not the mere fact that a method declared within a protocol is
being implemented.

Would this be something that is desirable to other users of the language?
Easy to implement?


(Brent Royal-Gordon) #2

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.

···

--
Brent Royal-Gordon
Architechies


(Howard Lovatt) #3

Personally I would like the following rules:

1. If a method implements or overrides any method in a class, struct, or
extension, whether declared in a protocol or class, then it must be tagged
with override.
2. If a method is implemented in an extension and not declared previously
in a protocol then in should be tagged final (this is another
swift-evolution proposal already)

If both were adopted then it would be clear what was happening.

At present the compiler also struggles, if you make a minor error when
overriding a protocol method all the compiler can do is tell you that the
struct/class does not conform. It doesn't tell you where the error is,
which might be in an extension in a different file. If the methods were
tagged with override the compiler would give a better error message and
importantly direct you to the problem.

···

On Wednesday, 6 January 2016, Xiaodi Wu via swift-evolution < swift-evolution@swift.org <javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>> wrote:

Dipping my toes in the water, so to speak, with a suggestion that came to
mind. Not an expert by any means, so hopefully this isn't too laughably off
the mark. As background, I work in the biomedical sciences; with few
exceptions, those of us who write code are non-experts who learn as we go
along. What's been attractive about Swift is that it's been designed with
approachability in mind for beginning coders and those with a rudimentary
understanding of languages in the C family. Difficulty in syntax and
sophistication of the computer science concepts exposed are hurdles that
can be overcome, but what keeps me up at night are potentially subtle
things maybe easy for the expert that I or my colleagues just might not
know about, which then lead to code that appears correct at first glance,
compiles, but executes in subtly unintended ways. Those things in my field
are what could lead to retracted papers, ruined careers, etc....

This is something along those lines; also somewhat of a reprise of a theme
that's been raised tangentially in a few threads within the past month
(e.g.:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001125.html),
but I think the particular solution I'm envisioning hasn't been put forward.

The issue at hand:

Consider the following (contrived) example (call it version 1)--

class Animal {
    func makeNoise() -> String {
        return "generic sound"
    }
}

class Cow: Animal {
    override func makeNoise() -> String {
        return "moo"
    }
}

class Sheep: Animal {
    override func makeNoise() -> String {
        return "bah"
    }
}

let cow = Cow()
cow.makeNoise() // "moo"
(cow as Animal).makeNoise() // "moo"

let farm: [Animal] = [Cow(), Cow(), Sheep()]
let noises: [String] = farm.map { $0.makeNoise() }
// ["moo", "moo", "bah"]

Now refactor to use a protocol. I'll give two versions, differing by a
single line.

Version 2A--

protocol Animal { }

extension Animal {
    func makeNoise() -> String {
        return "generic sound"
    }
}

class Cow: Animal {
    func makeNoise() -> String {
        return "moo"
    }
}

class Sheep: Animal {
    func makeNoise() -> String {
        return "bah"
    }
}

let cow = Cow()
cow.makeNoise() // "moo"
(cow as Animal).makeNoise() // "generic sound"

let farm: [Animal] = [Cow(), Cow(), Sheep()]
let noises: [String] = farm.map { $0.makeNoise() }
// ["generic sound", "generic sound", "generic sound"]

Version 2B--

protocol Animal {
    func makeNoise() -> String
}

extension Animal {
    func makeNoise() -> String {
        return "generic sound"
    }
}

class Cow: Animal {
    func makeNoise() -> String {
        return "moo"
    }
}

class Sheep: Animal {
    func makeNoise() -> String {
        return "bah"
    }
}

let cow = Cow()
cow.makeNoise() // "moo"
(cow as Animal).makeNoise() // "moo"

let farm: [Animal] = [Cow(), Cow(), Sheep()]
let noises: [String] = farm.map { $0.makeNoise() }
// ["moo", "moo", "bah"]

To be sure, this difference in behavior can be justified in a variety of
ways, but it is nonetheless a surprising result at first glance. Most
concerning is that it is possible to imagine a scenario in which the
protocol in question is one provided in a third-party library, or even the
Swift standard library, while I'm writing a struct or class that implements
that protocol.

Suppose that between versions of a third-party library the Animal protocol
changes from version 2A to version 2B. My struct or class that implements
the protocol would compile without changes, and cow.makeNoise() would even
give the same result, yet there would be differences in how my code works
that would be difficult to track down. An expert would be able to spot the
difference on examination of the protocol declaration, but one would have
to be knowledgeable already about this particular issue to know what to
look for. This seems like a gotcha that can be avoided.

Proposed solution:

I think others have tried to approach this from a different angle (see,
for example:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001933.html).
My view is that there are two points potentially to address.

(1) func makeNoise() -> String { ... } within the protocol extension
indicates two different things in versions 2A and 2B (since one is
dynamically dispatched and the other is not), yet the syntax is
indistinguishable.

(2) Within a class or struct implementing a protocol, a method with the
same name as that of a method in a protocol extension (potentially in
another file, maybe not written by the same person) behaves differently
depending on whether that method name is declared in the protocol itself
(potentially in a third file, written by a third person), yet the syntax is
indistinguishable within the implementing class or struct. If the protocol
changes, whether a method is dynamically dispatched or statically
dispatched could change too, yet code in a class or struct implementing
that protocol that now behaves differently compiles all the same;
implementors are not clued into the change and may not even be aware that
changes such as this could happen.

What I'm thinking is a light-touch fix that would address (2), which would
largely mitigate the consequences of (1). 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.

In other words, I propose that in the contrived example above, version 2B
(which behaves just like version 1) requires syntax just like that of
version 1 (in class Cow and class Sheep, override func makeNoise() ->
String { ... }). Meanwhile, version 2A, which doesn't quite behave like
version 1, forbids the same syntax. That way, anyone confused about what he
or she is getting into when implementing the protocol is notified at
compile time, and code that compiles in one scenario will not compile if
the underlying protocol declaration changes.

I suppose quite a good counterargument would be that protocols exist to be
implemented, and implementations of methods required for conformance to a
protocol shouldn't need another keyword. I would be inclined to agree, but
in this case I'd point out that what would trigger the requirement for use
of the override keyword is the presence of a default implementation being
overridden, not the mere fact that a method declared within a protocol is
being implemented.

Would this be something that is desirable to other users of the language?
Easy to implement?

--
  -- Howard.


(Xiaodi Wu) #4

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.

I think this is a great point and would be a con that I hadn't considered
in terms of Howard's suggestion that everything implementing a protocol
should have use a keyword (such as "override" or "implement").

I fear that I've explained my idea a little poorly. My thought was that
*only methods overriding something*--namely, a default implementation given
in a protocol extension--should be required to use the override keyword
when the method is dynamically dispatched.

It would remain very much possible to formalize an existing pattern
because, in the case of your example (unless I'm misunderstanding?), you
are not also providing a default implementation of the "min" and "max"
getters, and the IntXX structs would have nothing to override. Indeed,
you'd hardly be formalizing an existing pattern if you had to supply de
novo implementations! It's true that it's possible to do something in
today's Swift syntax that wouldn't be possible in my proposal. Namely, in
today's Swift syntax, it's possible to give a dynamically dispatched
default implementation of the min and max getters in an after-the-fact
formalization, but I have trouble seeing any circumstance in which that
would be necessary--unless I misunderstand, such a default implementation
can never be invoked?

···

On Tue, Jan 5, 2016 at 10:50 PM, Brent Royal-Gordon <brent@architechies.com> 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:
>(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.

--
Brent Royal-Gordon
Architechies


(Greg Parker) #5

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.

···

On Jan 5, 2016, at 8:50 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@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.

--
Greg Parker gparker@apple.com Runtime Wrangler


(Thorsten Seitz) #6

That is a very important point! Making classes or structs conform to a new protocol by an empty extension is a really important use case.

-Thorsten

···

Am 06.01.2016 um 05:50 schrieb Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org>:

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.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Xiaodi Wu) #7

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.

That would be really neat. On my wishlist though would be something
along the same lines going in the forward direction, where there's
some sort of distinction between a class or struct overriding a
dynamically dispatched default implementation for a method declared in
a protocol and a method that doesn't override anything but happens to
'shadow' or 'mask' a statically dispatched method in a protocol
extension that's never fully overridden. I guess the objection here is
that a change in syntax for that scenario would make new protocol
adoptions after the fact difficult; but there must be a way to have it
both ways...

···

On Wed, Jan 6, 2016 at 3:48 AM, Greg Parker <gparker@apple.com> wrote:

On Jan 5, 2016, at 8:50 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@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.

--
Greg Parker gparker@apple.com Runtime Wrangler


(Thorsten Seitz) #8

The pattern might exist for some existing classes or structs but it might still be useful for new classes or even for some existing ones to provide a default implementation.

-Thorsten

···

Am 06.01.2016 um 06:23 schrieb Xiaodi Wu via swift-evolution <swift-evolution@swift.org>:

It would remain very much possible to formalize an existing pattern because, in the case of your example (unless I'm misunderstanding?), you are not also providing a default implementation of the "min" and "max" getters, and the IntXX structs would have nothing to override. Indeed, you'd hardly be formalizing an existing pattern if you had to supply de novo implementations!


(Matthew Johnson) #9

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

···

On Jan 6, 2016, at 3:48 AM, Greg Parker via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 5, 2016, at 8:50 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

--
Greg Parker gparker@apple.com <mailto:gparker@apple.com> Runtime Wrangler

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Xiaodi Wu) #10

The pattern might exist for some existing classes or structs but it might still be useful for new classes or even for some existing ones to provide a default implementation.

I agree. It could be very useful in certain circumstances, and I agree
that any proposal that made this no longer possible would be a
non-starter. I had to think about this point for a bit; I hope I can
convince you that it would remain possible if overriding methods had
to use a keyword. The way it would be done would be valid code today,
and I think after some reflection that it's a superior way of doing
things even in today's Swift syntax because it's more explicit about
what's going on.

Example:
Given three existing struct types--

struct Foo {
    func boo() { print("foo boo") }
}
struct Bar { }
struct Baz { }

We wish to formalize after the fact, giving each type a method boo()
with a default implementation. Currently, this is valid Swift code--

protocol BooType {
    func boo()
}
extension BooType {
    func boo() { print("default boo") }
}
extension Foo: BooType { }
extension Bar: BooType { }
extension Baz: BooType { }

As you point out rightly, this would be invalid if we had to write
"override func boo()" in the body of struct Foo. However, this is
valid Swift code both in today's syntax and if my proposal were to be
implemented, and it is only one line longer--

protocol BooType {
    func boo()
}
protocol DefaultBooType: BooType { }
extension DefaultBooType {
    func boo() { print("default boo") }
}
extension Foo: BooType { }
extension Bar: DefaultBooType { }
extension Baz: DefaultBooType { }

I'd like to promote the second option as being superior even in
today's syntax. It is immediately clear to the reader that Foo().boo()
invokes a different method than Bar().boo(), even if the reader does
not have access to the original code for structs Foo, Bar, and Baz.
Suppose those structs were supplied in a third-party library that's
not well documented. It's plausible that a non-expert coder could try
to formalize after the fact and write an extension BooType
implementing boo() unaware that there is an overriding method in Foo.
In today's Swift syntax, the code would compile and behave subtly
differently from the author's expectations; as proposed, that code
would lead to a compile-time error. However, an expert coder who
intended to supply a default function but invoke any overriding
methods could write code that is almost as succinct but also
self-documenting, and in fact could do so today.

···

On Wed, Jan 6, 2016 at 12:45 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:

> Am 06.01.2016 um 06:23 schrieb Xiaodi Wu via swift-evolution <swift-evolution@swift.org>:
>
> It would remain very much possible to formalize an existing pattern because, in the case of your example (unless I'm misunderstanding?), you are not also providing a default implementation of the "min" and "max" getters, and the IntXX structs would have nothing to override. Indeed, you'd hardly be formalizing an existing pattern if you had to supply de novo implementations!

The pattern might exist for some existing classes or structs but it might still be useful for new classes or even for some existing ones to provide a default implementation.

-Thorsten


(Xiaodi Wu) #11

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

(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

(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@anandabits.com> wrote:

On Jan 6, 2016, at 3:48 AM, Greg Parker via swift-evolution > <swift-evolution@swift.org> wrote:

On Jan 5, 2016, at 8:50 PM, Brent Royal-Gordon via swift-evolution > <swift-evolution@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@apple.com Runtime Wrangler

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Brent Royal-Gordon) #12

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

But the same problem exists if you want to do this to `internal` types using a `private` protocol. There you *could* make the protocol `internal` and call `override` in all the right places, but if the protocol is an implementation detail of one particular file, why should you?

(Thanks for the term "retroactive modeling", by the way—I couldn't remember it.)

···

--
Brent Royal-Gordon
Architechies


(Howard Lovatt) #13

I like Greg Parkers suggestion, if the extension is of a type that is not
part of the project/library that is being developed then you don't need
override. This would allow after-the-fact extensions to library and
third-party structure/classes. It is also not confusing to human or
compiler, since this is not source code you are looking at (by definition).

···

On Thursday, 7 January 2016, Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

On Jan 6, 2016, at 3:48 AM, Greg Parker via swift-evolution < > swift-evolution@swift.org > <javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>> wrote:

On Jan 5, 2016, at 8:50 PM, Brent Royal-Gordon via swift-evolution < > swift-evolution@swift.org > <javascript:_e(%7B%7D,'cvml','swift-evolution@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@apple.com
<javascript:_e(%7B%7D,'cvml','gparker@apple.com');> Runtime Wrangler

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
<javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>
https://lists.swift.org/mailman/listinfo/swift-evolution

--
  -- Howard.


(Howard Lovatt) #14

Comments in-line below.

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

···

On Thursday, 7 January 2016, Xiaodi Wu via swift-evolution < swift-evolution@swift.org> wrote:

(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@anandabits.com > <javascript:;>> wrote:
>
> On Jan 6, 2016, at 3:48 AM, Greg Parker via swift-evolution > > <swift-evolution@swift.org <javascript:;>> wrote:
>
>
> On Jan 5, 2016, at 8:50 PM, Brent Royal-Gordon via swift-evolution > > <swift-evolution@swift.org <javascript:;>> 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@apple.com <javascript:;> Runtime Wrangler
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <javascript:;>
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <javascript:;>
https://lists.swift.org/mailman/listinfo/swift-evolution

--
  -- Howard.


(Xiaodi Wu) #15

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@gmail.com> wrote:

Comments in-line below.

On Thursday, 7 January 2016, Xiaodi Wu via swift-evolution > <swift-evolution@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@anandabits.com> >> wrote:
>
> On Jan 6, 2016, at 3:48 AM, Greg Parker via swift-evolution >> > <swift-evolution@swift.org> wrote:
>
>
> On Jan 5, 2016, at 8:50 PM, Brent Royal-Gordon via swift-evolution >> > <swift-evolution@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@apple.com Runtime Wrangler
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
  -- Howard.


(Howard Lovatt) #16

The point is that without the requirement of both final and override the
compiler doesn't know in detail what the problem is; just that there is a
problem, it doesn't have enough information (it doesn't know the
programmers intention - override and final clarify that intension). That is
irrespective of how the compiler is written.

···

On Thursday, 7 January 2016, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

> 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@gmail.com > <javascript:;>> wrote:
> Comments in-line below.
>
>
> On Thursday, 7 January 2016, Xiaodi Wu via swift-evolution > > <swift-evolution@swift.org <javascript:;>> 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@anandabits.com > <javascript:;>> > >> wrote:
>> >
>> > On Jan 6, 2016, at 3:48 AM, Greg Parker via swift-evolution > >> > <swift-evolution@swift.org <javascript:;>> wrote:
>> >
>> >
>> > On Jan 5, 2016, at 8:50 PM, Brent Royal-Gordon via swift-evolution > >> > <swift-evolution@swift.org <javascript:;>> 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@apple.com <javascript:;> Runtime Wrangler
>> >
>> >
>> > _______________________________________________
>> > swift-evolution mailing list
>> > swift-evolution@swift.org <javascript:;>
>> > https://lists.swift.org/mailman/listinfo/swift-evolution
>> >
>> >
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <javascript:;>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> --
> -- Howard.
>

--
  -- Howard.