[swift-evolution] Mark protocol methods with their protocol

Boris Wang kona.ming at gmail.com
Mon Sep 19 19:00:11 CDT 2016


swift mixed implemention of protocol method and other method,this triggered
the problem.

Compiler can't judge mis-spelled method. It think it's a new method.

Rust has no this problem:

Impl protocolName for className {
.....
}

linter can't check for mis-spelled methods, on the condition that there's
no explicit override syntax in
Swift.


Goffredo Marocchi via swift-evolution <swift-evolution at swift.org>于2016年9月20日
周二04:12写道:

> +1
>
> Sent from my iPhone
>
> On 19 Sep 2016, at 18:10, Vladimir.S via swift-evolution <
> 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.
>
> Opinions?
>
> Currently, there is a JIRA bug that Set does not conform to SetAlgebra. To
>
> fix this issue, someone simply needs to write `extension Set : SetAlgebra {
>
> }` and some tests. That's literally what the bug (filed by a core team
>
> member) tells you to do. It's a starter bug, and if someone hasn't taken it
>
> yet, you the reader could have a go at it. What's neat about Swift is that
>
> it's super easy to provide the same functionality in your own project
>
> without waiting on that bug to be fixed in Swift itself. You can simply
>
> write a single line of code. By contrast, if your proposal were to be
>
> implemented, this would become much more difficult.
>
>
> This is actively used in Swift today. For example, in the Swift
>
> implementation of NSScanner, you'll find the following lines:
>
>
> ```
>
> internal protocol _BitShiftable {
>
>    static func >>(lhs: Self, rhs: Self) -> Self
>
>    static func <<(lhs: Self, rhs: Self) -> Self
>
> }
>
>
> internal protocol _IntegerLike : Integer, _BitShiftable {
>
>    init(_ value: Int)
>
>    static var max: Self { get }
>
>    static var min: Self { get }
>
> }
>
>
> extension Int : _IntegerLike { }
>
> extension Int32 : _IntegerLike { }
>
> extension Int64 : _IntegerLike { }
>
> extension UInt32 : _IntegerLike { }
>
> extension UInt64 : _IntegerLike { }
>
> ```
>
>
> If we adopted your proposed syntax below, it would take considerably more
>
> lines of boilerplate code to express the same thing. The burden increases
>
> significantly with the complexity of the retroactive modeling. For
>
> instance, if the retroactively modeled protocol had 20 requirements and you
>
> were retroactively conforming 20 types, that'd be at least 400 lines of
>
> boilerplate.
>
>
>
>    Basically, the way I see it, if my class MyClass implements MyProtocol,
>
>    providing someRequiredFunc(), there’s an “ownership” chain there
>
>    (reading it backwards).
>
>
>    Now what happens if MyClass implements MyOtherProtocol, which also has
>
>    someRequiredFunc()? In that case, I want to MyClass as a
>
>    MyOtherProtocol and get another function pointer, which just happens to
>
>    have the same human-readable name as some other property. Just because
>
>    they have the same function signature, absolutely doesn’t mean they’re
>
>    the same thing.
>
>
>    Now, if we strongly bind all protocol conformances to the protocol they
>
>    implement, what happens to instance methods? They don’t belong to any
>
>    protocol, their parent is the class itself. If you have an instance
>
>    method called someRequiredFunc(), and you later add a conformance to
>
>    MyProtocol, you would need to declare that it belongs to MyProtocol. If
>
>    you don’t want it to be an API-breaking change, you have to provide a
>
>    thunk (or we could provide a shorthand syntax which emits thunks for
>
>    you) to let us know that MyClass::someRequiredFunc() is the same thing
>
>    as MyClass::MyProtocol::someRequiredFunc().
>
>
>
> Your argument is that two methods with the same name should not in any way
>
> conflict with each other. This is a fundamental change from the status quo.
>
> If we were to take your argument to its logical conclusion, any member A of
>
> a type T should be capable of being designated as the implementation of a
>
> requirement B of protocol P. In the most general case, two functions A and
>
> B shouldn't even need to take the same number of arguments, or arguments of
>
> the same type; you should be able to supply default arguments, or even
>
> write custom code that takes arguments for A and computes suitable
>
> arguments for B in order to forward A to B, and the language should allow
>
> you to designate A as an implementation of B. But that is simply not how
>
> Swift protocols are designed.
>
>
>
>    Let’s take an example where retroactive modelling could go wrong.
>
>    You’ve got different teams working on different parts of an App, and
>
>    they’ve all got their own convention for “copy()”. Sometimes it’s a
>
>    deep-copy, sometimes a shallow-copy, sometimes it’s used in a fragile
>
>    way for a specific case, whatever. Now you want to go and clean that up
>
>    by creating a “Copyable” protocol with codified guarantees. Some
>
>    objects may already conform, others may need tweaks, and some may want
>
>    both behaviours simultaneously (preserving the old,
>
>    non-Copytable-compliant behaviour until the next API break), depending
>
>    on how you look at the object. A system like this allows all of those
>
>    different ways of looking at the object live together. You could have
>
>    the old, non-comforming API as an extension with a FIXME to delete it
>
>    for version 2.
>
>
>
> Even if you design a protocol called Copyable, you still need to explicitly
>
> extend concrete types in order to conform to Copyable. Swift does not
>
> automagically make anything conform to your protocol. If you choose
>
> *explicitly* to conform different types that don't guarantee the same
>
> semantics, and then you erroneously assume that they all have the same
>
> semantics even though you *explicitly* chose types that don't have the same
>
> semantics, you're the one who shot yourself in the foot, so to speak. It's
>
> not the fault of Swift at all.
>
>
>
>    I think it’s pretty arcane that members of a type are resolved only by
>
>    their names. If you want to provide types which allow flexible views of
>
>    data, each view of that data needs to be completely free in its
>
>    expressivity.
>
>
>    I would actually like to see a syntax like:
>
>
>    ```
>
>    let testObject = MyClass()
>
>    let testMyProto = testObject.MyProtocol // the protocol-witness table
>
>    for testObject as a MyProtocol.
>
>
>    testObject.MyProtocol.someRequiredFunc() // that’s one function
>
>    testObject.someRequiredFunc() // is a different function. May happen to
>
>    have the same implementation as above if MyProtocol was retroactively
>
>    modelled.
>
>    ```
>
>
>    I think it would fit well with the dispatch system for protocol
>
>    extensions, too. I sometimes have code like the following:
>
>
>    ```
>
>    protocol Base {}
>
>    protocol Derived : Base {}
>
>
>    extension Base {
>
>      func doSomething() { … }
>
>    }
>
>    extension Derived {
>
>      func doSomething() {
>
>>
>       (self as Base).doSomething() // Would be better if we could say
>
>    “self.Base.doSomething()” to disambiguate instead of casting.
>
>      }
>
>    }
>
>    ```
>
>
>
> This is a complete redesign of protocols in Swift. With the emphasis on
>
> minimizing source-breaking changes, I doubt such a change would be in scope
>
> for any phase of Swift unless you could show an overwhelming benefit.
>
>
>    So yeah, a big +1 to marking protocol methods with their protocol
>
>    (whatever the syntax ends up looking like), and actually I’d take it
>
>    further and bake them in to the ABI. That also makes it relevant for
>
>    Swift 4 phase 1.
>
>
>    Karl
>
>
>
>
> _______________________________________________
>
> swift-evolution mailing list
>
> swift-evolution at swift.org
>
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160920/df72d1a7/attachment.html>


More information about the swift-evolution mailing list