> Am 24.08.2016 um 21:35 schrieb Xiaodi Wu via swift-evolution 
> <[email protected]>:
> 
>> On Wed, Aug 24, 2016 at 1:59 PM, Jonathan Hull <[email protected]> wrote:
>> 
>>> On Aug 24, 2016, at 7:48 AM, Xiaodi Wu <[email protected]> wrote:
>>> 
>>>> On Wed, Aug 24, 2016 at 3:39 AM, Jonathan Hull <[email protected]> wrote:
>>>> 
>>>>> On Aug 23, 2016, at 8:35 AM, Xiaodi Wu <[email protected]> wrote:
>>>>> 
>>>>>> On Tue, Aug 23, 2016 at 3:02 AM, Jonathan Hull <[email protected]> wrote:
>>>>>> 
>>>>>>> On Aug 22, 2016, at 11:32 PM, Xiaodi Wu <[email protected]> wrote:
>>>>>>> 
>>>>>>>> On Mon, Aug 22, 2016 at 11:59 PM, Jonathan Hull via swift-evolution 
>>>>>>>> <[email protected]> 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.
>>>>>>> 
>>>>>>> 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?
>>>>>> 
>>>>>> 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.
>>>>>> 
>>>>>> 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).
>>>>> 
>>>>> 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.
>>>>> 
>>>>> 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.
>>>>> 
>>>>> 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.
>>>> 
>>>> 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.
>>>> 
>>>> 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.
>>> 
>>> Ah, well this isn't exactly the diamond problem you're talking about here. 
>>> Instead, I think, we have a fundamental disagreement. I think I've been 
>>> told that this opinion of mine is 'insane'--but I hold to it:
>> 
>> Well you asked for an additional example besides the diamond problem… so no 
>> it isn’t.  I did include a diamond problem example further down though…
>  
> Sorry, I wasn't asking for an example _besides_ the diamond problem. I was 
> asking for more information about a concrete scenario, diamond problem or 
> not, where an existing technique could not resolve the conflict (for 
> instance, a scenario when you controlled neither of two conflicting 
> protocols, and where no satisfactory alternative design existed that could 
> avoid conforming a single type to both protocols).
> 
>> 
>>> Protocols are not merely a vehicle for delivering a reusable bag of code. 
>>> One of its most essential purposes is to constrain the shape or API of its 
>>> conforming types. Therefore, it is a feature, not a bug, that with every 
>>> choice of name in a protocol you foreclose the possibility of composing 
>>> that protocol with others that might have colliding names.
>>> 
>>> Currently, if you the protocol vendor have made the decision that `image` 
>>> "makes the most sense in the protocol's context", you must have considered 
>>> whether it would be absurd for a conforming type to have another use for 
>>> `image`. If it would be absurd, then `image`

I find it a little bit strange to require from a protocol designer to foresee 
all future uses of a protocol. IMO protocols are not bags of code but 
encapsulate a certain (typically fine grained) semantic. How this semantic will 
be coupled with other semantics (i.e. protocols) is widely open.


>>> is the appropriate name for your protocol requirement and any other word 
>>> would truly be redundant. But, if this is only one of many plausible 
>>> images, then `somethingImage` or `imageOfSomething` *is* the appropriate 
>>> name, and trying to shorten the name isn't at all consistent with Swift 
>>> guidelines but rather an incorrect attempt to prioritize brevity over 
>>> clarity.
>> 
>> Most things that conform would have ‘image’, and it would have exactly the 
>> same semantics as my protocol. Thus their ‘image’ would provide conformance 
>> without additional work.  But I have to worry about name collisions, so now 
>> I have to defensively call it ‘imageOfSomething', which they now have to 
>> implement to call their ‘image’ method.
>> 
>> 
>>> What you're arguing is that protocol designers should be able to design 
>>> protocols without regard for how they will compose with others in 
>>> conforming types, relying on a new member-renaming feature instead. But, as 
>>> you point out, you can already use a protocol as a mere bag of code by 
>>> naming all members with unique, prefixed names, then have conforming types 
>>> forward their own choice of names to these.
>> 
>> No, I am arguing that protocol authors should design protocols in the way 
>> which makes the behavior/semantics of the protocol the most obvious to the 
>> caller.  95% of the time there won’t be collisions, but occasionally there 
>> will be and we have to have a plan for that.
>> 
>> 
>>> This member-renaming feature you propose would enhance the aesthetic 
>>> pleasure of the protocol designer, allowing simple names that don't ever 
>>> have to appear in the public API of a concrete type to be used for a 
>>> protocol member without placing any restrictions on the API of conforming 
>>> types. However, I don't see anything wrong with the current hand-prefixing 
>>> method being enshrined as "best practice" for the bag-of-code approach to 
>>> protocols. If, as you predict, a growing third-party code ecosystem makes 
>>> name collisions worse, then in fact having uniquely distinguishable 
>>> prefixed members would be less confusing than having conforming types 
>>> renaming protocol members as a matter of course.
>> 
>> You are arguing that namespace collisions are a feature instead of a bug?  
>> Did you feel that way about ObjectiveC’s lack of name spacing?
> 
> My argument is about protocols specifically: I understand that a major 
> feature of protocols is that they make guarantees regarding the API of 
> conforming types. In rare cases, two guarantees may conflict, but I do not 
> consider that conflict to be a bug per se, as it is the inevitable result of 
> what it means to have guarantees, i.e. it is part and parcel of the feature. 
> In order to provide a way of resolving conflicting requirements in protocols, 
> your solution eliminates the API-guaranteeing feature of protocols altogether.
> 
> I can't comment about Objective-C, because I've never written a single line 
> of it.
>  
>> I don’t think it is anywhere near as confusing as you suggest. As I 
>> mentioned before, if you cast it to the protocol, then the original names 
>> will still work.
> 
> Except when you can't cast to a protocol existential, as is the case with any 
> protocol with Self or associated type requirements.

This is a separate problem which will be solved once we have existential types.
Furhermore the argument still holds when the protocol is being used as type 
constrained.


>  
>> If you are trying to type the original name on the typed conformer, then 
>> showing the renamed version (with an indication of the renaming) in 
>> autocomplete should teach the change and clear up any confusion.
> 
> Mine isn't an argument about usability or learnability. It's a 
> philosophical/design point: what are protocols for? My answer: among other 
> uses, for constraining the API of conforming types. Perhaps this view is 
> incompatible with the view that protocols should support additional 
> mixin-like features.

I don't think this has anything to do with mixins. It is just the general 
problem of being able to combine protocols which have been designed 
independently from each other.


> 
>>>> 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.
>>>> 
>>>> 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()’ )
>>>> 
>>>> 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.
>>> 
>>> I think Charles's solution is pretty nice, but he's right that the API 
>>> surface area will have to grow. I don't know his original use case, so I 
>>> don't know how ugly I'd find the final solution to be in that scenario. In 
>>> this particular example, I'd say that having `linearWalk()` and 
>>> `randomWalk()` distinguished seems pretty sensible and an overall win for 
>>> clarity. If the same vendor controlled all three protocols, then `Walkable` 
>>> could have the `walk()` requirement removed altogether for even more 
>>> clarity.
>> 
>> So you would remove 'walk()' from Walkable to avoid the name collision in 
>> this one case, when ‘walk()’ is Walkable’s entire reason for being?
> 
> No, `walk()` is not Walkable's entire reason for being. Protocols guarantee 
> semantics also. A `Walkable` protocol without any required members would 
> still have a reason for being: conforming types are walkable.
> 
> On the other hand, given that Walkable certainly would have associated type 
> requriements, if you considered that `walk()` _was_ Walkable's entire reason 
> for being *and* you could rename `walk()` in any conforming type, how is that 
> different from not having a `walk()` requirement at all?

Generic methods using a type constrained by Walkable can call `walk()` on it. 
The same will be possible for variables declared with existential types in the 
future and it already applies for protocols without associated type or Self 
requirements.

-Thorsten 


> 
>> Also, you would lose polymorphism.
>> 
>> 
>> 
>>> Also, just a hunch, but I suspect your hypothetical would never hold. Could 
>>> you envision how the requirements for RandomWalkable might be such that 
>>> it's possible to implement an efficient _default_ implementation of a 
>>> random walk for any of several conforming data structures, but only one of 
>>> these data structures is LinearWalkable, _and_ such a linear walk is 
>>> efficient using another _default_implementation for an overlapping but not 
>>> identical set of data structures? It's not mere trivia here, because the 
>>> crux of your argument is that there exist default implementations that 
>>> require copying and pasting into conforming types (and sufficiently 
>>> efficient default implementations so that copying and pasting is 
>>> appropriate rather than implementing a more efficient version). More likely 
>>> in diamond problem scenarios, I think, colliding members are going to be 
>>> properties or methods either without default implementations or than need 
>>> to supply more efficient versions of default implementations anyway.
>> 
>> Based on what?  There is a reason the diamond problem has a name (and a 
>> wikipedia entry).  Charles just said he ran into a problem like this.  I 
>> have run into it in the past as well.
> 
> Sure, and returning to my question above: could you share details about where 
> you've run into this?
> 
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to