Default implementation for protocols

Proposal

···

=======
Allow protocols to define a default implementation, e.g.:

  protocol Complex {
    default var re: Double = 0
    default var im: Double = 0
    var mag: Double { return sqrt(re * re + im * im) }
    // ...
  }

Which gets translated to:

  protocol Complex {
    var re: Double { get, set }
    var im: Double { get, set }
    var mag: Double { get }
    // ...
  }

  extension Complex {
    var mag: Double { return sqrt(re * re + im * im) }
    // ...
  }

  struct _DefaultComplex: Complex { // Some private name
    var re: Double = 0
    var im: Double = 0
    // ...
  }

In use:

  let complex = Complex()

Gets translated into:

  let complex = _DefaultComplex()

Motivation

  1. You often have a default implementation for a protocol, much like a
function argument might have a default value. Therefore this proposal adds
convenience by saving boilerplate.
  2. It is difficult to name a protocol if there is a natural default
implementation. For example the natural name for the protocol that all
integral types inherited from is Integer, but that is also the natural name
for the default implementation. This tension between protocol and default
implementation name leads to strange naming conventions like IntegerType
for the protocol; we already know it is a type (it is a protocol after
all!). This is just a form of Hungarian notation; most people find
Hungarian obfuscates the code rather than clarifying.

Details

  1. Change protocols so that protocol methods are dynamically dispatched,
when overridden in an extension.
  2. Change protocols so that all implementations and overrides of a
protocol method require the override keyword.
  3. Allow protocols to directly specify an implementation as well as via
an extension, also see point 1 and note dynamic dispatch.
  4. Allow via the default keyword protocols to define properties
(including stored), initialisers, and functions that are part of the
default implementation of the protocol but not the protocol itself.
  5. In the case of a default stored property the
  6. Allow the protocol name to be used to call the initialiser and in such
cases use the default implementation.

--
  -- Howard.

Hi Howard,

This is a desired feature, but a surprising amount of implementation effort blocks “just doing it”. We hope that this will happen in Swift 3, but we’ll see how things work out with the other generics system improvements.

-Chris

···

On Jan 30, 2016, at 4:48 PM, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

Proposal

Allow protocols to define a default implementation, e.g.:

  protocol Complex {
    default var re: Double = 0
    default var im: Double = 0
    var mag: Double { return sqrt(re * re + im * im) }
    // ...
  }

Thanks for the feedback.

···

On Sunday, 31 January 2016, Chris Lattner <clattner@apple.com> wrote:

> On Jan 30, 2016, at 4:48 PM, Howard Lovatt via swift-evolution < > swift-evolution@swift.org <javascript:;>> wrote:
>
> Proposal
> =======
> Allow protocols to define a default implementation, e.g.:
>
> protocol Complex {
> default var re: Double = 0
> default var im: Double = 0
> var mag: Double { return sqrt(re * re + im * im) }
> // ...
> }

Hi Howard,

This is a desired feature, but a surprising amount of implementation
effort blocks “just doing it”. We hope that this will happen in Swift 3,
but we’ll see how things work out with the other generics system
improvements.

-Chris

--
  -- Howard.

See inline

Proposal

Allow protocols to define a default implementation, e.g.:

  protocol Complex {
    default var re: Double = 0
    default var im: Double = 0
    var mag: Double { return sqrt(re * re + im * im) }
    // ...
  }

Shouldn't there be a "default" before "var mag: Double ..."?

Which gets translated to:

  protocol Complex {
    var re: Double { get, set }
    var im: Double { get, set }
    var mag: Double { get }
    // ...
  }

  extension Complex {
    var mag: Double { return sqrt(re * re + im * im) }
    // ...
  }

  struct _DefaultComplex: Complex { // Some private name
    var re: Double = 0
    var im: Double = 0
    // ...
  }

In use:

  let complex = Complex()

Gets translated into:

  let complex = _DefaultComplex()

Motivation

  1. You often have a default implementation for a protocol, much like a function argument might have a default value. Therefore this proposal adds convenience by saving boilerplate.
  2. It is difficult to name a protocol if there is a natural default implementation. For example the natural name for the protocol that all integral types inherited from is Integer, but that is also the natural name for the default implementation. This tension between protocol and default implementation name leads to strange naming conventions like IntegerType for the protocol; we already know it is a type (it is a protocol after all!). This is just a form of Hungarian notation; most people find Hungarian obfuscates the code rather than clarifying.

Details

  1. Change protocols so that protocol methods are dynamically dispatched, when overridden in an extension.

That should probably be a separate proposal to make the current one more incremental.

  2. Change protocols so that all implementations and overrides of a protocol method require the override keyword.

I would definitely love to see something like an override keyword. Although there could be confusion with method overrides in classes. Currently I'm fine with "override".

  3. Allow protocols to directly specify an implementation as well as via an extension, also see point 1 and note dynamic dispatch.

I like the separation between "required signatures" and default implementations. The protocol body shouldn't be cluttered with implementations. Extensions also group default implementations for different type constraints.

  4. Allow via the default keyword protocols to define properties (including stored), initialisers, and functions that are part of the default implementation of the protocol but not the protocol itself.

I'm skeptical about stored properties in protocols (multiple inheritance => diamond problem).

A "default" keyword would definitely help to distinguish between properties/methods with default implementations and the ones without them.

  5. In the case of a default stored property the

... ? :)

  6. Allow the protocol name to be used to call the initialiser and in such cases use the default implementation.

What will happen if not all requirements are fulfilled by default implementations? Also consider multiple inheritance.
Should there be an "init" which takes the remaining properties?

This reminds me of the "memberwise init" proposal...

Best regards
- Maximilian

···

Am 31.01.2016 um 01:48 schrieb Howard Lovatt via swift-evolution <swift-evolution@swift.org>:

--
  -- Howard.

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

Inline below.

See inline

Proposal

Allow protocols to define a default implementation, e.g.:

  protocol Complex {
    default var re: Double = 0
    default var im: Double = 0
    var mag: Double { return sqrt(re * re + im * im) }
    // ...
  }

Shouldn't there be a "default" before "var mag: Double ..."?

No. It gets translated into a protocol member and an extension to the
protocol. In the proposal, if default was put infant of the line then it
wouldn't appear in the protocol nor the extension, just in the default
struct.

     Which gets translated to:

  protocol Complex {
    var re: Double { get, set }
    var im: Double { get, set }
    var mag: Double { get }
    // ...
  }

  extension Complex {
    var mag: Double { return sqrt(re * re + im * im) }
    // ...
  }

  struct _DefaultComplex: Complex { // Some private name
    var re: Double = 0
    var im: Double = 0
    // ...
  }

In use:

  let complex = Complex()

Gets translated into:

  let complex = _DefaultComplex()

Motivation

  1. You often have a default implementation for a protocol, much like a
function argument might have a default value. Therefore this proposal adds
convenience by saving boilerplate.
  2. It is difficult to name a protocol if there is a natural default
implementation. For example the natural name for the protocol that all
integral types inherited from is Integer, but that is also the natural name
for the default implementation. This tension between protocol and default
implementation name leads to strange naming conventions like IntegerType
for the protocol; we already know it is a type (it is a protocol after
all!). This is just a form of Hungarian notation; most people find
Hungarian obfuscates the code rather than clarifying.

Details

  1. Change protocols so that protocol methods are dynamically dispatched,
when overridden in an extension.

That should probably be a separate proposal to make the current one more
incremental.

Yes. There has been discussion of this in another thread. This proposal
would build on the previous one and I should have just referenced that
proposal.

  2. Change protocols so that all implementations and overrides of a
protocol method require the override keyword.

I would definitely love to see something *like* an override keyword.
Although there could be confusion with method overrides in classes.
Currently I'm fine with "override".

Java, Scala, use override in both contacts - no problems.

  3. Allow protocols to directly specify an implementation as well as via
an extension, also see point 1 and note dynamic dispatch.

I like the separation between "required signatures" and default
implementations. The protocol body shouldn't be cluttered with
implementations. Extensions also group default implementations for
different type constraints.

Not taking that away. However it is quite a lot of boiler plate for a small
class and as acknowledged by Chris Lattner already on the things to do
list.

  4. Allow via the default keyword protocols to define properties
(including stored), initialisers, and functions that are part of the
default implementation of the protocol but not the protocol itself.

I'm skeptical about stored properties in protocols (multiple inheritance
=> diamond problem).

No stored property in the protocol, just getter and setters. The actual
stored property is only in the struct.

A "default" keyword would definitely help to distinguish between properties/methods
with default implementations and the ones without them.

Yes default is necessary to distinguish the two uses.

  5. In the case of a default stored property the

... ? :)

Oops. Meant to say: 5. In the case of a default stored property the
protocol has the appropriate calculated property, nothing is added to the
extension, and the struct has the actual stored property.

  6. Allow the protocol name to be used to call the initialiser and in
such cases use the default implementation.

What will happen if not all requirements are fulfilled by default
implementations? Also consider multiple inheritance.
Should there be an "init" which takes the remaining properties?

A. If the default implementation does not fulfil all the requirements then
it is an error, just like a struct has to fulfil all the requirements.

B. It only has multiple inheritance of protocols, like Swift already has.
The default is a struct, therefore both final and can only inherit from
protocols.

C. You need to write default inits as necessary to make a valid protocol.
For example if you have a private stored property then it won't be in the
protocol but in the struct and all the inits will need to ensure it is
initialised, just like normal.

This reminds me of the "memberwise init" proposal...

Not sure I follow your thinking on this.

···

On 1 February 2016 at 07:53, Maximilian Hünenberger <m.huenenberger@me.com> wrote:

Am 31.01.2016 um 01:48 schrieb Howard Lovatt via swift-evolution < > swift-evolution@swift.org>:

Best regards
- Maximilian

--
  -- Howard.

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

--
  -- Howard.