[swift-evolution] Renaming for Protocol Conformance

Xiaodi Wu xiaodi.wu at gmail.com
Fri Aug 26 01:15:06 CDT 2016


On Wed, Aug 24, 2016 at 3:28 PM, Karl via swift-evolution <
swift-evolution at swift.org> wrote:

>
> On 24 Aug 2016, at 20:38, Douglas Gregor via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>
> On Aug 22, 2016, at 9:59 PM, Jonathan Hull via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> Hi everyone,
>
> We talked about this before when we were discussing mixins, and there
> seemed to be generally positive feelings towards it as a feature for the
> future.  I am fairly certain this affects the ABI though, so I thought I
> would bring it up now.
>
> If two protocols have methods/properties with the same name, but different
> signatures, we need a way to distinguish between them when attempting to
> conform to both.
>
> protocol A {
> var x:Int {get set}
> }
>
> protocol B {
> var x:Double {get set}
> }
>
>
> I believe that this can happen, and it is unfortunate that Swift has no
> mechanism for dealing with it today. However, I agree with Xiaodi that your
> proposal would be much stronger with real-world examples rather than
> theoretical ones.
>
> One possibility is to allow a struct/class/enum to conform to the protocol
> while renaming one (or both) of the clashing methods:
>
> struct C: A,B {
> var x:Int
> var y:Double implements B.x
> }
>
> The conforming method/property would still have to have the same
> signature, but could have a different name (and parameter labels).  It
> would also allow protocol methods which have identical signatures and
> semantics, but different names to be implemented using the same method (i.e
> ‘implements D.z & E.w’).
>
> When something is cast to the protocol (say ‘as B’), then calling the
> property (e.g. ‘x’) would end up calling the implementation of the renamed
> property ( ‘y’ in this example) on the conforming type.
>
>
> Sure. Calling through the protocol type will get whatever method/property
> satisfied the protocol requirement. Yes, there are limits here due to
> protocols with associated types and Self requirements, but I fully expect
> those to go away at some point with generalized existentials.
>
> I think we would also want a way to retroactively conform using existing
> properties/methods in an extension declaring conformance.  Not sure what
> the best syntax for that would be.  Off the top of my head (though I would
> love to have something with less cruft):
>
> extension D:B {
> @conform(to: B.x, with: D.y)
> }
>
> or maybe just:
>
> extension D:B {
> D.y implements B.x
> }
>
>
> All of this is merely to start the discussion, so feel free to propose
> better syntax or a more elegant solution...
>
>
> C# has a much narrower solution that lets you qualify the method
> declaration (rather than doing a full rename), e.g.,
>
> struct C : A {
>   var x: Int
>   var y: Double
> }
>
> extension C : B {
>   var B.x: Double {
>     get { return y }
>     set { y = newValue }
>   }
> }
>
> They have some examples at:
>
> https://msdn.microsoft.com/en-us/library/aa288461(v=vs.71).aspx
>
> One would have to figure out what the name-lookup rules are, of course,
> but this might allow us to solve the problem without introducing a
> generalized renaming mechanism.
>
> - Doug
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> +1 to the C# mechanism (I think it’s basically what I proposed earlier).
> Resolving protocol conformance by name is soooo Objective-C. Swift has a
> much stronger protocol system, and members which belong to a protocol
> should **belong** to that protocol (have it mangled in to the name,
> MyType__MyProtocol__MyMember, etc. As a shorthand, when the corresponding
> protocol is unambiguous you can declare or use it directly
> (MyType.MyMember).
>
> I’m very much against renaming. It’s a hack; we want a solution. That
> applies to all instances of renaming - here, in protocol conformances, and
> in general with imported types (there was a proposal some months ago which
> involved renaming members when importing).
>
> The two most important things for programmers are how well they know the
> language, and how well they know the libraries they are using. Renaming
> makes the latter basically useless. Somebody doesn’t like the long names in
> Apple’s SDK, and suddenly UITableView becomes Table or even just an emoji
> (why not?). The code you know and patterns you expect become a bunch of
> alien hieroglyphics which looked neat and terse to the person writing it
> but requires extensive study by anybody else.
>
> Renaming is just bad, bad, bad. I’ll argue strongly against adding any
> kind of symbol renaming to Swift whatsoever for as long as I’m active in
> the community (except across language barriers, like with @objc(<name>),
> because the symbols don’t match up anyway so there’s no prior knowledge to
> break — in fact it’s usually used to retain older APIs and make transitions
> *less* breaking).
>

After some reflection, I think I largely agree with Karl on this point. A
C#-like explicit implementation mechanism might be the way to go; it solves
the issue of colliding names without introducing the difficulties that
arise from arbitrary renaming.

Where I would disagree with Karl would be on mangling the protocol names
into member names; as I wrote above, I strongly hold to the view that it's
important that protocols guarantee the API of conforming types, so I think
that protocol requirements should be in the same namespace as all other
type members *unless* something else is explicitly necessary due to a
collision. However, in the end, the disagreement here is more conceptual
than practical, as everyday use of the feature would be largely similar in
any case.

Based on that view, however, I'd go a step further in
simplifying/rationalizing the C#-like mechanism, like so:

* I'd propose that conformance to a protocol can be either as it is in
Swift 3 (let's call it "direct") or it can be what C# would call explicit
(let's call it "indirect", just for good measure); unlike C#, this choice
would refer to conformance as a whole, not to implementation of specific
members (although this is more of a notional difference from C#, since as
proposed below, specific members may or may not be accessible directly
without casting).

* Members declared directly on the type that match the requirements of an
"indirectly conformed" protocol will satisfy those requirements, but any
remaining requirements not satisfied in that manner (for instance, due to
colliding names) must be implemented in an extension that explicitly
declares indirect conformance. For example:

```
protocol A {
  var x: Int { get }
  var y: Int { get }
}

protocol B {
  var x: Double { get }
  var y: Int { get }
}

struct S : A {
  var x: Int { return 42 }
  var y: Int { return 43 }
  // we cannot have S conform to B just yet
  // because we can't re-declare `x` as a property of type Double
}

extension S : indirect B {
  var x: Double { return -42 }
  // note that `y` is satisfied by the implementation above
}
```

* Members declared in an extension adding an "indirect" conformance to a
protocol can only be accessed after the type is cast to the corresponding
existential type. In the example above, `S.x` is an Int (and is the same as
`(S as A).x`) and has value 42, but `(S as B).x` is a Double and has value
-42.0. Meanwhile, `S.y` can be accessed directly or indirectly as either
`(S as A).y` or `(S as B).y` and has value 43.

* Until generics are completed, only protocols without Self or associated
type requirements can be used as an existential, so for now let's limit
indirect conformances to protocols without Self or associated type
requirements; this limit should be relaxed in tandem with the
implementation of generalized existentials.

Would this simplified scheme go far enough in addressing the original issue?


Karl
>
> _______________________________________________
> 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/20160826/ff0ba8a7/attachment.html>


More information about the swift-evolution mailing list