<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Aug 23, 2016, at 8:35 AM, Xiaodi Wu <<a href="mailto:xiaodi.wu@gmail.com" class="">xiaodi.wu@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">On Tue, Aug 23, 2016 at 3:02 AM, Jonathan Hull<span class="Apple-converted-space"> </span><span dir="ltr" class=""><<a href="mailto:jhull@gbis.com" target="_blank" class="">jhull@gbis.com</a>></span><span class="Apple-converted-space"> </span>wrote:<br class=""><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><br class=""><div class=""><span class=""><blockquote type="cite" class=""><div class="">On Aug 22, 2016, at 11:32 PM, Xiaodi Wu <<a href="mailto:xiaodi.wu@gmail.com" target="_blank" class="">xiaodi.wu@gmail.com</a>> wrote:</div><br class=""><div class=""><div dir="ltr" class="">On Mon, Aug 22, 2016 at 11:59 PM, Jonathan Hull via swift-evolution<span class="Apple-converted-space"> </span><span dir="ltr" class=""><<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>></span><span class="Apple-converted-space"> </span>wrote:<br class=""><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;">Hi everyone,<br class=""><br class="">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.</blockquote><div class=""><br class=""></div><div class="">It's been some time now since the original discussion, so perhaps you could refresh our collective memory (or at least, mine): although it *seems* like this feature might be useful, I can't recall a concrete use case where I've felt like I needed this feature--do you have some examples?</div></div></div></div></div></blockquote><div class=""><br class=""></div></span><div class="">Ideally, the biggest use is that it helps to (partially) solve the diamond problem (and similar issues) by forcing/allowing disambiguation when there are multiple protocols being conformed to. This will become more of an issue if we allow protocols or extensions to add storage. Your proposed syntax actually does a better job of it than mine because mine was always shown as attached to some sort of implementation, whereas yours could potentially allow access to a default implementation under a new name.</div><div class=""><br class=""></div><div class="">Other than that, it generally allows us to bypass/mitigate conflicts between protocols. In the current version, you are unable to conform to both protocols (either because it won’t compile or because you can’t satisfy the semantics of both protocols) without designing the protocols together to avoid conflicts. (I have definitely had to go back and rename/refactor properties on a protocol for this reason… which I couldn’t have done if I didn’t control both protocols).</div></div></div></blockquote><div class=""><br class=""></div><div class="">I understand something of the difficulty of confronting the diamond problem. As I wrote above, I'm inclined to believe that this proposed feature would help solve a real issue. However, the point I'm trying to make is that, on reflection, I have never actually been hampered by the lack of this feature, and so I'd like to continue the discussion to get a fuller sense of just how impactful this proposal would be, both positive and negative.</div><div class=""><br class=""></div><div class="">It's true, of course, that if you control at least one of two protocols (you don't need to control both protocols), it is trivially easy to cause this problem to occur, but as you point out it is also possible to resolve the problem by re-designing the protocol you control. I'm inclined to think (without evidence, admittedly) that re-designing to remove the conflict, where possible, would actually be the superior option in most cases.</div><div class=""><br class=""></div><div class="">My question was: have you actually run into a scenario that necessitates the feature you propose because you controlled neither conflicting protocol? I think it would strengthen the proposal greatly to have a concrete, uncontrived example.</div></div></div></div></div></blockquote><div><br class=""></div><div>Right now I commonly have to hand-namespace protocol methods/properties to avoid conflicts. So instead of having ‘var image:UIImage’ (which is the name which makes the most sense in the protocol’s context), I have ‘var protocolNameImage:UIImage’. There are lots of things which have common properties like ‘count’ which have to be called ‘somethingCount’ or ‘countOfSomething’. In the context of the protocol, these names are full of redundant words (especially when measured against the new naming guidelines). We are all used to doing this for Objective C, but it feels out of place in Swift.</div><div><br class=""></div><div>This will become a much more serious issue as the third-party code ecosystem grows. Without some capability like this, you will have frameworks which can’t be used together (or at least with the same object). I would hate to see a ‘best practice’ emerge of adding 3 letter prefixes to all protocol methods to get around compatibility issues.</div><div><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class=""><div class="">Take a look at Eiffel’s ‘rename’ & ’select’ features for similar functionality and use-cases.</div><div class=""><br class=""></div><div class="">Ultimately, this is a step in the direction of having true mixins.</div><span class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class=""></div></div></div></div></div></blockquote></span></div></div></blockquote><div class=""><br class=""></div><div class="">Sure, maybe. I couldn't evaluate that claim. I'm inclined to favor the proposal, but it'd have to stand on its own merits, not as a step to an as-yet undesigned feature.</div></div></div></div></div></blockquote><div><br class=""></div><div>This would be part of that design. We have to start somewhere. A journey of 1000 miles begins with a single step.</div><div><br class=""></div><div><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class=""><span class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class=""> I am fairly certain this affects the ABI though, so I thought I would bring it up now.</div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><br class="">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.<br class=""><br class=""> <span class="Apple-converted-space"> </span>protocol A {<br class=""> <span class="Apple-converted-space"> </span>var x:Int {get set}<br class=""> <span class="Apple-converted-space"> </span>}<br class=""><br class=""> <span class="Apple-converted-space"> </span>protocol B {<br class=""> <span class="Apple-converted-space"> </span>var x:Double {get set}<br class=""> <span class="Apple-converted-space"> </span>}<br class=""></blockquote><div class=""><br class=""></div><div class="">Methods can be overloaded that differ in arguments or return type, so it seems like this problem mainly exists with *properties* that differ in type--am I wrong?</div></div></div></div></div></blockquote><div class=""><br class=""></div></span><div class="">There is also the case of functions with the same name and signature, but different semantics. There may be no single implementation which simultaneously satisfies the semantics for both protocols. By renaming one of the functions, we are able to provide separate implementations for each requirement (which allows both protocols to function as intended).</div></div></div></blockquote><div class=""><br class=""></div><div class="">True. However, putting on my critical hat, this seems like we're stretching to provide support for an anti-pattern. It'd be nice to have an example where one runs into the motivating problem *and* where the proposed feature promotes a _better_ design than is currently possible, rather than making a bad design compile.</div><div class=""><br class=""></div><div class="">At this point, I'm imagining scenarios where a user is trying to conform a type MyAnimal to both Biped and Quadruped, then worrying that `walk()` has two semantics: something has already gone deeply wrong IMO.</div><div class=""><br class=""></div><div class="">[Yes, I know there are animals that can sometimes walk on two or four legs. The point here is that the protocols were clearly designed to model animals at a certain level of detail, while it appears that the user writing `MyAnimal` wants to model the animal at a different level of detail than either protocol was designed to handle. You might have specific qualms about this particular hypothetical, but I think you can pick out the general point that there is a much larger problem inherent in the design than the specific problem regarding two colliding method signatures.]</div></div></div></div></div></blockquote><div><br class=""></div><div>To take your example of walk(). Perhaps we have a protocol ‘Walkable’ which refers to any data structure where the nodes can be walked using the ‘walk()’ function. It is easy to imagine two different protocols A & B which specialize on this in different ways (say LinearWalkable & RandomWalkable), and both add some methods/properties and use those to provide efficient default implementations. At some point, you may run into a data structure which could easily be walked in both ways.</div><div><br class=""></div><div>As things are right now, you couldn’t inherit from both protocols. While you could add new ‘linearWalk()’ & ‘randomWalk()’ to the protocols respectively (cluttering their interface), there is still the issue of what to do when 'walk()’ is called. You can’t rename walk() in the originating protocols because it comes from their common ancestor. Much better to force one (or both) of the methods to be renamed on the conforming data structure. That keeps the interfaces of the protocols clean and makes the options available on the data structure clearer (e.g. ‘walk()’ & ‘randomWalk()’ )</div><div><br class=""></div><div>What I have had to do in the current version is inherit from the original protocol and then copy and paste the default implementations from the specialized versions. Now my code has been duplicated and is harder to maintain. We can do better.</div><div><br class=""></div><div><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class=""><div class="">There may also be functions in different protocols with different names but the same semantics and signature. This will allow a single implementation to satisfy both protocols without duplication.</div></div></div></blockquote><div class=""><br class=""></div><div class="">This is a poor argument IMO. You can already implement foo() and then have bar() forward to foo() with trivial effort and really minimal boilerplate. It's an existing solution, and a more general solution because it doesn't require matching signatures. Also, it's a better solution IMO because it preserves the notion that a type T : Fooable, Barrable provides the full API guaranteed by Fooable and Barrable.</div><div class=""><br class=""></div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class=""><div class="">Finally, we may want to rename an inherited default implementation to avoid conflicting with another protocol's default implementation in cases where we don’t want to override it.</div></div></div></blockquote><div class=""><br class=""></div><div class="">Yes, I think this would be handy. I can't think of an existing way to do this, and I expect it might make a big difference in designing good protocols. So here, I think we have a strong argument.</div><div class=""><br class=""></div><div class="">Again, though, could we find a concrete example of how this feature would promoter a better design of an actual type and/or protocol?</div><div class=""><br class=""></div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class=""><span class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class=""> One possibility is to allow a struct/class/enum to conform to the protocol while renaming one (or both) of the clashing methods:</div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><br class=""> <span class="Apple-converted-space"> </span>struct C: A,B {<br class=""> <span class="Apple-converted-space"> </span>var x:Int<br class=""> <span class="Apple-converted-space"> </span>var y:Double implements B.x<br class=""> <span class="Apple-converted-space"> </span>}<br class=""><br class="">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’).<br class=""><br class="">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.<br class=""></blockquote><div class=""><br class=""></div><div class="">Reflecting on this proposed change, it occurs to me that something of value would be lost, and I think that this something is actually rather valuable:</div><div class=""><br class=""></div><div class="">Today, when I see that a type conforms to (for example) Sequence, I know that certain methods and/or properties exist on that type. Protocol conformance guarantees a certain API, not just certain semantics.</div></div></div></div></div></blockquote><div class=""><br class=""></div></span><div class="">It isn’t actually lost, however. When working with it as a Sequence (for example), that API would be intact using the original names. It is only when working with it as its own type that the renaming would have an effect.</div></div></div></blockquote><div class=""><br class=""></div><div class="">That is not my point. With this proposal, knowing that MyGreatType conforms to Sequence would no longer yield any information as to the MyGreatType API. That is definitely something lost and we should acknowledge that.</div><div class=""><br class=""></div><div class="">Also, recall that Sequence has Self or associated type requirements. So:</div><div class=""><br class=""></div><div class="">```</div><div class="">let m = MyGreatType()</div><div class="">// There is nothing I can write here to use the Sequence API with `m`, IIUC;</div><div class="">// however, depending on how this feature is designed, I *might* be able to</div><div class="">// call a generic function that operates on a type `T : Sequence` and work</div><div class="">// with `m` that way.</div><div class="">```</div></div></div></div></div></blockquote><div><br class=""></div><div>I get what you are saying, but this is really asking for an Xcode feature to better show the generated interfaces. Code completion will still work properly.</div><div><br class=""></div><div><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="gmail_extra"><div class="gmail_quote"><div class=""><br class=""></div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class=""><span class=""><blockquote type="cite" class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">Perhaps one way to mitigate this loss would be to have any renamed members listed *in the declaration of conformance*, something like this (with some additional bikeshedding):</div><div class=""><br class=""></div><div class="">```</div><div class="">struct MyGreatType : Sequence (count => length) {</div><div class=""> <span class="Apple-converted-space"> </span>// MyGreatType conforms to Sequence but renames `count` to `length`</div><div class="">}</div><div class="">```</div></div></div></div></blockquote><div class=""><br class=""></div></span><div class="">Yes, putting it in the conformance declaration is a definite possibility we should consider.</div><span class=""><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class=""><br class=""></div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;">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):<br class=""><br class=""> <span class="Apple-converted-space"> </span>extension D:B {<br class=""> <span class="Apple-converted-space"> </span>@conform(to: B.x, with: D.y)<br class=""> <span class="Apple-converted-space"> </span>}<br class=""><br class="">or maybe just:<br class=""><br class=""> <span class="Apple-converted-space"> </span>extension D:B {<br class=""> <span class="Apple-converted-space"> </span>D.y implements B.x<br class=""> <span class="Apple-converted-space"> </span>}<br class=""></blockquote><div class=""><br class=""></div><div class="">If renamed members are declared along with protocol conformance, then the syntax for retroactive modeling follows naturally:</div><div class=""><br class=""></div><div class="">```</div><div class="">extension D : B (x => y) { }</div><div class="">// again, the actual notation here is ugly</div><div class="">// but the underlying idea, I think, is worth considering</div><div class="">```</div></div></div></div></div></blockquote><div class=""><br class=""></div></span><div class="">Yup</div><div class=""><br class=""></div><div class="">One thing I like about this is that it helps to solve the diamond problem. ‘x’ could be a default implementation in B which D does not override. I think this is an important case which my original proposal didn’t address fully.</div><div class=""><br class=""></div><div class="">We should keep bikeshedding the syntax though...</div></div><br class=""><div class="">Thanks,</div><div class="">Jon</div></div></blockquote></div></div></div></div></blockquote></div><br class=""></body></html>