> On 17 Sep 2016, at 01:45, Xiaodi Wu via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> I absolutely agree that it's a problem worth solving. However, the question 
> is whether a particular proposed design solves the problem and avoids 
> previously stated weaknesses. What I'm saying here is that, so far, the 
> conversation in this thread has involved reiterating already-proposed designs 
> that have been critiqued. It's really quite tiring for me too to repeat the 
> same critique when someone raises the same proposal a second or third time.
> 
> It's possible that it makes sense to have a separate syntax for retroactive 
> modeling. I haven't been able to come up with one that seems reasonable to 
> me, or I would have written to this list to propose it. Do you have such a 
> design in mind?
> On Fri, Sep 16, 2016 at 16:59 Charles Srstka <cocoa...@charlessoft.com 
> <mailto:cocoa...@charlessoft.com>> wrote:
> On Sep 16, 2016, at 4:08 PM, Xiaodi Wu via swift-evolution 
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> We've had this discussion on the list multiple times already. The gist of 
>> the difficulty here is that most proposals for a mandatory keyword don't 
>> permit retroactive modeling, so it's a no-go. On the other hand, the core 
>> team seems to take a dim view to optional syntax, since that's more in the 
>> ballpark of linters.
> 
> Numerous solutions to your objection have been proposed; you always simply 
> dismiss all of them in favor of your dogmatic stance. It’s really quite 
> tiring. You can have this and support retroactive modeling; you just might 
> need to have a separate syntax for retroactive conformances. You keep 
> bringing that up as a hard-and-fast objection, but you know what? Maybe 
> retroactive conformances should have a separate syntax, because they’re not 
> saying the same thing! One is saying "here are some methods that will make 
> this type conform to this protocol”, where the other is saying “this type 
> already has the methods that conform to this protocol somewhere.” These are 
> not the same thing, and it might be confusing to see a conformance 
> declaration and assume it’s the former when it’s actually the latter, and 
> then have trouble finding the conformances. Maybe it would actually make your 
> code clearer if retroactive conformances were required to declare “this 
> method exists somewhere else already.” Maybe you could even command-click on 
> it and jump to the actual declaration. Anything would be better than the 
> current situation, because:
> 
> The reason this keeps coming up is because it’s a real problem. I myself have 
> started taking up the practice of always using copy-and-paste to declare 
> conformances to protocols, because otherwise the chances of mistyping 
> something and having the bug not manifest itself until runtime is simply too 
> high. This is not a “linter” problem; this affects basic functionality and 
> makes protocols, honestly, really dangerous to use. For a language that bills 
> itself as “protocol-oriented”, it’s really quite damning that its protocol 
> support is this brittle and fragile compared to its support for traditional 
> inheritance. I’ve been bitten by this enough times by now to somewhat regret 
> the decision to go with a protocol-based design. This is a real shame because 
> conceptually, the idea of Swift’s protocol-based design is really cool.
> 
> Charles
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution


I don’t see what the big problem about retroactive modelling is.

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

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.

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

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to