[swift-evolution] Mark protocol methods with their protocol

Vladimir.S svabox at gmail.com
Tue Sep 20 08:17:08 CDT 2016


On 20.09.2016 3:03, Xiaodi Wu via swift-evolution wrote:
> I definitely think Vladimir's suggestion is a great starting point, IMO.
> However, I think it could be improved in one key respect where previous
> proposals using `override` are superior. Namely, the proposed `implement`
> keyword adds no additional safety when a type implements a protocol
> requirement that doesn't have a default implementation. This is because, if

Yes, *at the moment of writing* the type's code there could be no default 
implementation for protocol requirement. But, *at the moment of 
compilation* such default implementation could appear.

Let's discuss such scenario in case we'll take your suggestion:

You got SomeClass.swift file, 3rd party file you don't want to change or 
changes are not allowed. Content:

public protocol SomeProtocol {
	func foo()

public class SomeClass : SomeProtocol {
	func foo() {...} // no default implementation *at the moment of writing*, 
no need in `overload`

Now, you adds SomeClass.swift file to your project and in some *other* file 
you write:

extension SomeProtocol {
	func foo() {...}

As you see, you don't control the SomeClass.swift but you suggest in this 
case SomeClass.foo() should be defined with `override`.

With 'implement' SomeClass.foo() will be marked initially and will save us 
if protocol's requirement PLUS default implementation changed.

> there's a "near-miss" typo in the function signature, an error is already
> generated at compile time because the type doesn't conform to the stated
> protocol. Currently, the error is very unhelpful, but IMO that's a

Even, if `implement` will not add safety in case there is no default 
implementation of protocol's requirement *now*, it will add safety if you 
decide to add such default implementation at some point of time or in some 
other point of your project. And this `implement` will save us in this 
case, as you expresses your intention explicitly and compiler will check this.

> straight-up bug; improving the diagnostics for that error can be done
> without evolution.
> On the other hand, if we require `implement`, the simplest use case of
> conforming a type to a protocol with no default implementations would take
> more effort but provide no benefit to justify that additional effort.

I don't believe the requirement to add just one word `implement` on the 
same line with method/prop declaration would take more effort to conform to 
protocol. I don't see see real big difference in these lines:

class Foo : Bar {
	func foo() {...}

class Foo : Bar {
	implement func foo() {...}

But I see that foo is a protocol requirement and compiler will help me with 
this. Also this add clarity when you read some one's code.

> Moreover (I think a core team member has expressed this more elegantly in
> the past), there's the philosophical point that POP represents the
> theoretical process by which we discover and express our discovery that
> certain types happen to share common semantic characteristics. In that
> conception of POP, it would be backwards to declare a certain member as
> fulfilling certain protocol requirements.

Well.. I do believe we need some golden middle between "theoretical 
process" and C++ ;-) I.e. we are discussing a real-word programming 
language, which we use to build low-level utils, web backend applications, 
macOS apps, iOS apps etc. IMO we need a balance between a shiny theory and 
ugly bugs we *will* have because this theory don't allow our compiler to 
help us.

Probably there is another perfect way to solve the initial problem, 
probably core team already invented something cool and we just don't know 
about this yet. But for now I think its worth to add the `implement` 
keyword to Swift.

> So, if such a source breaking change were to be in scope for Swift, I would
> suggest modifying Vladimir's proposal to use `override` instead and

If the community and core team will accept the idea to mark method defined 
in type as protocol's requirement (without any relation to existence of 
default implementation) only with `override` - I think this also will be a 
good solution. I.e. when we see `override` in type definition, we 
understand that this type implements something that exists in its "super" 
type in wide sense i.e. in its super class or in one of its protocols.

So, personally I don't insist on `implement` word, but propose some 
'marker' to mark methods in type implemented exactly as implementation for 
some requirement.

Probably this really could be `override` - as Swift propose itself as POP 
language, there should be no big difference if we override a method of 
super class or 'override' a method of one of protocols. Just like 
`override` for super class method, `override` for protocol implementation 
method is here just because this method *depend* on what is defined in 
conformed protocol.

But again, `override` IMO should not depend on if there is a default 
implementation in protocol.

> requiring the keyword only when a default implementation is being
> overridden. To accommodate retroactive conformance, we could either propose
> that `extension Foo : Bar` is automatically understood to contain members
> that override default implementations (as Vladimir has essentially
> suggested), or stipulate that we must write `extension Foo : override Bar`.
> This has the advantage of not introducing an additional keyword and avoids
> the seemingly reduplicative spelling `extension Foo : implement Bar` (for
> what else would an `extension Foo : Bar` reasonably do but implement the
> requirements of Bar?).
> On Mon, Sep 19, 2016 at 3:10 PM, Goffredo Marocchi via swift-evolution
> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>     If Swift 4 will make it impossible to tackle this again, I do not think
>     discussing this can be avoided for Swift 3.1... I am afraid we are
>     rushing into Swift 4 a bit too quickly, but perhaps it is just silly
>     old me :).
>     Sent from my iPhone
>     On 19 Sep 2016, at 19:18, Charles Srstka via swift-evolution
>     <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>>     On Sep 19, 2016, at 12:10 PM, Vladimir.S via swift-evolution
>>>     <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>>     On 17.09.2016 6:32, Xiaodi Wu via swift-evolution wrote:
>>>>     Let me give a concrete example of how retroactively modeling is used.
>>>     Karl is suggesting interesting but complex and IMO too much
>>>     code-breaking idea that I don't believe can be implemented at all in
>>>     a reasonable amount of time to be a part of Swift as soon as
>>>     possible, to address the discussed issue with protocols.
>>>     I wonder what objections could be made on the solution proposed
>>>     below, which should solve a major(IMO) number of issues with
>>>     protocol conformance and introduce only 1 keyword. Such solution
>>>     will make Swift better as Protocol-Oriented language and later we
>>>     can even improve it, but it can already solve a big number of issues:
>>>     1. As soon as possible we add 'implement' keyword which is required
>>>     to mark method/property that was defined in type or extension
>>>     exactly to conform to some protocol.
>>>     2. The 'implement' required only at a moment of 'direct'
>>>     conformance, i.e. when you declare methods/props of the
>>>     type/extension that explicitly conformed to protocol.
>>>     3. Retrospective conformance will not require this keyword and will
>>>     work for now just like it is working today.
>>>     4. Later, if this will be possible at all, we can extend this model
>>>     to support separate implementation of protocols with same
>>>     requirements in the same type, explicit protocol name in implemented
>>>     methods/props and improvements for retrospective conformance. For
>>>     example some variants for *future* improvements:
>>>     4.1 Different implementation for different protocols
>>>     class Foo : ProtocolA, ProtocolB {
>>>      implement(ProtocolA) func foo() {...}
>>>      implement(ProtocolB) func foo() {...}
>>>     }
>>>     class Foo : ProtocolA, ProtocolB {
>>>      implement ProtocolA {
>>>     func foo() {...}
>>>      }
>>>      implement ProtocolB {
>>>     func foo() {...}
>>>      }
>>>     }
>>>     etc
>>>     4.2 Retrospective conformance: What is the main problem with
>>>     retrospective conformance? As I see it now(correct me, if I missing
>>>     something), the problem arises in such situation:
>>>     * we *expect* that some method(s) in type will play the role of
>>>     implementation of protocol's requirements, so we retrospectively
>>>     conform that type to the protocol.
>>>     * but protocol has default implementation for its requirements
>>>     * and type's methods, that we *expect* to play roles for protocol
>>>     implementation, has different parameters or slightly different
>>>     method name at all.
>>>     I.e. when we have this set of code logic:
>>>     type T {
>>>      func foo()
>>>     }
>>>     protocol P {
>>>      func foo(x: Int)
>>>     }
>>>     extension P {
>>>      func foo(x: Int) {...}
>>>     }
>>>     extension T : P { // expect foo in T will play role of P.foo
>>>     }
>>>     I support the opinion that it is not an option to require to
>>>     explicitly list conformed methods/props in type extension for
>>>     retrospective conformance.
>>>     But I do believe we need a way to *express our intention* regarding
>>>     the retrospective conformance: do we expect that type already
>>>     contains implementation for some protocol's requirements OR we are
>>>     aware that protocol can have defaults for some methods and our type
>>>     does not contains some implementations.
>>>     So, the solution here IMO is some syntax to express that intention.
>>>     Right now I think that we can use current syntax "extension T : P"
>>>     to keep it working as it now works: "I'm aware of all the names,
>>>     defaults etc. Treat this as usually you did". But for example
>>>     something like "extension T: implement P {..}" or "extension T:
>>>     P(implement *) {..}" will say that we *expect* that all requirements
>>>     of P protocol should be implemented inside T type. Or some syntax
>>>     inside extension to specify the list of methods/props we expect to
>>>     be implemented in T. Or "extension T : P(implement foo, bar(x:y:))
>>>     {..}".. Should be discussed.
>>>     But again, IMO this could be discussed later, after we'll have
>>>     'implement' for most important place - in type definition for
>>>     method/prop that we created exactly for the conformed protocol.
>>     I would be completely +1 on this.
>>     Charles
>>     _______________________________________________
>>     swift-evolution mailing list
>>     swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>     https://lists.swift.org/mailman/listinfo/swift-evolution
>>     <https://lists.swift.org/mailman/listinfo/swift-evolution>
>     _______________________________________________
>     swift-evolution mailing list
>     swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>     https://lists.swift.org/mailman/listinfo/swift-evolution
>     <https://lists.swift.org/mailman/listinfo/swift-evolution>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

More information about the swift-evolution mailing list