Good arguments, Tony, you have convinced me on all points. Transient is the way 
to go. Thank you for your patience!

-Thorsten

> Am 12.09.2017 um 16:38 schrieb Tony Allevato via swift-evolution 
> <[email protected]>:
> 
> 
> 
>> On Mon, Sep 11, 2017 at 10:05 PM Gwendal Roué <[email protected]> wrote:
>>>>> 
>>>>> This doesn't align with how Swift views the role of protocols, though. 
>>>>> One of the criteria that the core team has said they look for in a 
>>>>> protocol is "what generic algorithms would be written using this 
>>>>> protocol?" AutoSynthesize doesn't satisfy that—there are no generic 
>>>>> algorithms that you would write with AutoEquatable that differ from what 
>>>>> you would write with Equatable.
>>>> 
>>>> And so everybody has to swallow implicit and non-avoidable code synthesis 
>>>> and shut up?
>>> 
>>> That's not what I said. I simply pointed out one of the barriers to getting 
>>> a new protocol added to the language.
>>> 
>>> Code synthesis is explicitly opt-in and quite avoidable—you either don't 
>>> conform to the protocol, or you conform to the protocol and provide your 
>>> own implementation. What folks are differing on is whether there should 
>>> have to be *two* explicit switches that you flip instead of one.
>> 
>> No. One does not add a protocol conformance by whim. One adds a protocol 
>> conformance by need. So the conformance to the protocol is a *given* in our 
>> analysis of the consequence of code synthesis. You can not say "just don't 
>> adopt it".
>> 
>> As soon as I type the protocol name, I get synthesis. That's the reason why 
>> the synthesized code is implicit. The synthesis is explicitly written in the 
>> protocol documentation, if you want. But not in the programmer's code.
>> 
>> I did use "non-avoidable" badly, you're right: one can avoid it, by 
>> providing its custom implementation.
>> 
>> So the code synthesis out of a mere protocol adoption *is* implicit.
>> 
>>> Let's imagine a pie. The whole pie is the set of all Swift types. Some 
>>> slice of that pie is the subset of those types that satisfy the conditions 
>>> that allow one of our protocols to be synthesized. Now that slice of pie 
>>> can be sliced again, into the subset of types where (1) the synthesized 
>>> implementation is correct both in terms of strict value and of business 
>>> logic, and (2) the subset where it is correct in terms of strict value but 
>>> is not the right business logic because of something like transient data.
>> 
>> Yes.
>> 
>>> What we have to consider is, how large is slice (2) relative to the whole 
>>> pie, *and* what is the likelihood that developers are going to mistakenly 
>>> conform to the protocol without providing their own implementation, *and* 
>>> is the added complexity worth protecting against this case?
>> 
>> That's quite a difficult job: do you think you can evaluate this likelihood?
>> 
>> Explicit synthesis has big advantage: it avoids this question entirely.
>> 
>> Remember that the main problem with slide (2) is that developers can not 
>> *learn* to avoid it.
>> 
>> For each type is slide (2) there is a probability that it comes into 
>> existence with a forgotten explicit protocol adoption. And this probability 
>> will not go down as people learn Swift and discover the existence of slide 
>> (2). Why? because this probability is driven by unavoidable human behaviors:
>> - developer doesn't see the problem (a programmer mistake)
>> - the developper plans to add explicit conformance later and happens to 
>> forget (carelessness)
>> - a developper extends an existing type with a transient property, and 
>> doesn't add the explicit protocol conformance that has become required.
>> 
>> Case 2 and 3 bite even experienced developers. And they can't be improved by 
>> learning.
>> 
>> Looks like the problem is better defined as an ergonomics issue, now.
>> 
>>> If someone can show me something that points to accidental synthesized 
>>> implementations being a significant barrier to smooth development in Swift, 
>>> I'm more than happy to consider that evidence. But right now, this all 
>>> seems hypothetical ("I'm worried that...") and what's being proposed is 
>>> adding complexity to the language (an entirely new axis of protocol 
>>> conformance) that would (1) solve a problem that may not exist to any great 
>>> degree, and (2) does not address the fact that if that problem does indeed 
>>> exist, then the same problem just as likely exists with certain 
>>> non-synthesized default implementations.
>> 
>> There is this sample code by Thorsten Seitz with a cached property which is 
>> quite simple and clear : 
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170911/039684.html
>> 
>> This is the sample code that had me enter the "worried" camp.'
> 
> I really like Thorsten's example, because it actually proves that requiring 
> explicit derivation is NOT the correct approach here. (Let's set aside the 
> fact that Optionals prevent synthesis because we don't have conditional 
> conformances yet, and assume that we've gotten that feature as well for the 
> sake of argument.)
> 
> Let's look at two scenarios:
> 
> 1) Imagine I have a value type with a number of simple Equatable properties. 
> In a world where synthesis is explicit, I tell that value type to "derive 
> Equatable". Everything is fine. Later, I decide to add some cache property 
> like in Thorsten's example, and that property just happens to also be 
> Equatable. After doing so, the correct thing to do would be to remove the 
> "derive" part and provide my custom implementation. But if I forget to do 
> that, the synthesized operator still exists and applies to that type. If 
> you're arguing that "derive Equatable" is better because its explicitness 
> prevents errors, you must also accept that there are possibly just as many 
> cases where that explicitness does *not* prevent errors.
> 
> 2) Imagine I have a value type with 10 Equatable properties and one caching 
> property that also happens to be Equatable. The solution being proposed here 
> says that I'm better off with explicit synthesis because if I conform that 
> type to Equatable without "derive", I get an error, and then I can provide my 
> own custom implementation. But I have to provide that custom implementation 
> *anyway* to ignore the caching property even if we don't make synthesis 
> explicit. Making it explicit hasn't saved me any work—it's only given me a 
> compiler error for a problem that I already knew I needed to resolve. If we 
> tack on Hashable and Codable to that type, then I still have to write a 
> significant amount of boilerplate for those custom operations. Furthermore, 
> if synthesis is explicit, I have *more* work because I have to declare it 
> explicitly even for types where the problem above does not occur.
> 
> So, making derivation explicit is simply a non-useful dodge that doesn't 
> solve the underlying problem, which is this: Swift's type system currently 
> does not distinguish between Equatable properties that *do* contribute to the 
> "value" of their containing instance vs. Equatable properties that *do not* 
> contribute to the "value" of their containing instance. It's the difference 
> between behavior based on a type and additional business logic implemented on 
> top of those types.
> 
> So, what I'm trying to encourage people to see is this: saying "there are 
> some cases where synthesis is risky because it's incompatible with certain 
> semantics, so let's make it explicit everywhere" is trying to fix the wrong 
> problem. What we should be looking at is "how do we give Swift the additional 
> semantic information it needs to make the appropriate decision about what to 
> synthesize?"
> 
> That's where concepts like "transient" come in. If I have an 
> Equatable/Hashable/Codable type with 10 properties and one cache property, I 
> *still* want the synthesis for those first 10 properties. I don't want the 
> presence of *one* property to force me to write all of that boilerplate 
> myself. I just want to tell the compiler which properties to ignore.
> 
> Imagine you're a stranger reading the code to such a type for the first time. 
> Which would be easier for you to quickly understand? The version with custom 
> implementations of ==, hashValue, init(from:), and encode(to:) all covering 
> 10 or more properties that you have to read through to figure out what's 
> being ignored (and make sure that the author has done so correctly), or the 
> version that conforms to those protocols, does not contain a custom 
> implementation, and has each transient property clearly marked? The latter is 
> more concise and "transient" carries semantic weight that gets buried in a 
> handwritten implementation.
> 
> Here's a fun exercise—you can actually write something like "transient" 
> without any additional language support today: 
> https://gist.github.com/allevato/e1aab2b7b2ced72431c3cf4de71d306d. A big 
> drawback to this Transient type is that it's not as easy to use as an 
> Optional because of the additional sugar that Swift provides for the latter, 
> but one could expand it with some helper properties and methods to sugar it 
> up the best that the language will allow today.
> 
> I would wager that this concept, either as a wrapper type or as a built-in 
> property attribute, would solve a significant majority of cases where 
> synthesis is viewed to be "risky". If we accept that premise, then we can 
> back to our slice of pie and all we're left with in terms of "risky" types 
> are "types that contain properties that conform to a certain protocol but are 
> not really transient but also shouldn't be included verbatim in synthesized 
> operations". I'm struggling to imagine a type that fits that description, so 
> if they do exist, it's doubtful that they're a common enough problem to 
> warrant introducing more complexity into the protocol conformance system.
> 
>  
>> 
>> Gwendal
> _______________________________________________
> 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