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

I have nothing against small protocols with a defined purpose, on the contrary I am accustomed to type classes in Haskell which are typically very small.

The problem is that these "default" protocols do not serve a well defined purpose - they only exist to work around a deficiency in expressibility.

The point about the protocol not being under my control is the following (actually it is more about the extension with the default implementation not being under my control): imagine the protocol and especially the extension with default implementations for methods of that protocol is a third party protocol, i.e. protocol BooType and extension BooType are part of a third party library. In that case I cannot split off the default implementations into sub protocols.

Maybe some concise syntax can be found to bind the existing implementation to the protocol when conforming existing classes or structs to a protocol, like Greg Parker suggested.

-Thorsten

···

Am 06. Januar 2016 um 10:50 schrieb Xiaodi Wu xiaodi.wu@gmail.com:

That's a good argument, but I'm not convinced: not only do I have to define
additional protocols ("DefaultXXX") but in the worst case I have to do this
for each method declared in my protocol (which makes naming these default
protocols even worse, because XXX now has to represent the method), i.e.

protocol BooType {
func someBoo()
func anotherBoo()
func yetAnotherBoo()
}

when given:

struct Foo {
func someBoo() { print("foo boo") }
}
struct Bar {
func anotherBoo() { print("bar boo") }
}
struct Baz {
func anotherBoo() { print("baz boo") }
}

I would have to define all of the following:

protocol DefaultBooTypeSomeBoo : BooType { }
extension DefaultBooTypeSomeBoo {
func someBoo() { print("some boo") }
}
protocol DefaultBooTypeAnotherBoo : BooType { }
extension DefaultBooTypeAnotherBoo {
func anotherBoo() { print("another boo") }
}
protocol DefaultBooTypeYetAnotherBoo : BooType { }
extension DefaultBooTypeYetAnotherBoo {
func yetAnotherBoo() { print("yet another boo") }
}

Even worse: if the protocol itself is not under my control I cannot even do
this (not even for the simple case you demonstrated)!

-Thorsten

Am 06. Januar 2016 um 09:36 schrieb Xiaodi Wu xiaodi.wu@gmail.com:

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
You're quite right: in the worst case, the number of protocols you
would need would be linear to the number of methods. It's not the
best, I will concede. It does seem to be rather the "Swifty" way,
though. At least, if we follow the example of the Swift standard
library, it's not discouraged. Consider that the protocol hierarchy
for Int already has 26 protocols
(http://blog.krzyzanowskim.com/2015/03/01/swift_madness_of_generic_integer/).
What harm is there in another 3 or 4, or even 10--provided that each
is clearly named, serves a defined purpose, and is composed together
in something of a logical way?

I don't understand your point about controlling the protocol. Perhaps
you could explain? As far as I can tell, in my example BooType doesn't
need to be under your control or modified. If you extend Bar with
DefaultBooType, then (Bar is BooType == true).

On Wed, Jan 6, 2016 at 3:32 AM, Thorsten Seitz tseitz42@icloud.com wrote:

Yes, I see now your point about the protocol and extension being
third-party. That is a major problem indeed. I agree with you that
Greg Parker has suggested probably the most promising way forward on
this. Certainly not as easy as I'd imagined it to be.

···

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

I have nothing against small protocols with a defined purpose, on the
contrary I am accustomed to type classes in Haskell which are typically very
small.
The problem is that these "default" protocols do not serve a well defined
purpose - they only exist to work around a deficiency in expressibility.

The point about the protocol not being under my control is the following
(actually it is more about the extension with the default implementation not
being under my control): imagine the protocol and especially the extension
with default implementations for methods of that protocol is a third party
protocol, i.e. protocol BooType and extension BooType are part of a third
party library. In that case I cannot split off the default implementations
into sub protocols.

Maybe some concise syntax can be found to bind the existing implementation
to the protocol when conforming existing classes or structs to a protocol,
like Greg Parker suggested.

-Thorsten

Am 06. Januar 2016 um 10:50 schrieb Xiaodi Wu <xiaodi.wu@gmail.com>:

You're quite right: in the worst case, the number of protocols you
would need would be linear to the number of methods. It's not the
best, I will concede. It does seem to be rather the "Swifty" way,
though. At least, if we follow the example of the Swift standard
library, it's not discouraged. Consider that the protocol hierarchy
for Int already has 26 protocols
(http://blog.krzyzanowskim.com/2015/03/01/swift_madness_of_generic_integer/\).
What harm is there in another 3 or 4, or even 10--provided that each
is clearly named, serves a defined purpose, and is composed together
in something of a logical way?

I don't understand your point about controlling the protocol. Perhaps
you could explain? As far as I can tell, in my example BooType doesn't
need to be under your control or modified. If you extend Bar with
DefaultBooType, then (Bar is BooType == true).

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

That's a good argument, but I'm not convinced: not only do I have to define

additional protocols ("DefaultXXX") but in the worst case I have to do this

for each method declared in my protocol (which makes naming these default

protocols even worse, because XXX now has to represent the method), i.e.

protocol BooType {

func someBoo()

func anotherBoo()

func yetAnotherBoo()

}

when given:

struct Foo {

func someBoo() { print("foo boo") }

}

struct Bar {

func anotherBoo() { print("bar boo") }

}

struct Baz {

func anotherBoo() { print("baz boo") }

}

I would have to define all of the following:

protocol DefaultBooTypeSomeBoo : BooType { }

extension DefaultBooTypeSomeBoo {

func someBoo() { print("some boo") }

}

protocol DefaultBooTypeAnotherBoo : BooType { }

extension DefaultBooTypeAnotherBoo {

func anotherBoo() { print("another boo") }

}

protocol DefaultBooTypeYetAnotherBoo : BooType { }

extension DefaultBooTypeYetAnotherBoo {

func yetAnotherBoo() { print("yet another boo") }

}

Even worse: if the protocol itself is not under my control I cannot even do

this (not even for the simple case you demonstrated)!

-Thorsten

Am 06. Januar 2016 um 09:36 schrieb Xiaodi Wu <xiaodi.wu@gmail.com>:

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