> On Sep 12, 2017, at 8:07 PM, Tony Allevato via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> But all that stuff about custom attributes and metaprogramming introspection 
> is a big topic of it's own that isn't going to be solved in Swift 5, so this 
> is a bit of a digression. :)

Is it really a digression, though? Seems like with source-compatibility being 
essentially required going forward, it's important to nail this stuff down 
sooner rather than later if we want a nice, consistent language for The Future™.

I mean, the idea of writing "@adjective var noun: Type" to indicate that a 
certain variable shouldn't take place in code synthesis seems fairly safe to 
me, but proving $Idea1 is generalizable without stepping on $Idea2 is outside 
my area of expertise.



> On Sep 12, 2017, at 8:07 PM, Tony Allevato via swift-evolution 
> <swift-evolution@swift.org> wrote:
> On Tue, Sep 12, 2017 at 7:10 PM Xiaodi Wu <xiaodi...@gmail.com 
> <mailto:xiaodi...@gmail.com>> wrote:
> On Tue, Sep 12, 2017 at 9:58 AM, Thorsten Seitz via swift-evolution 
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
> Good arguments, Tony, you have convinced me on all points. Transient is the 
> way to go. Thank you for your patience!
> 
> On many points, I agree with Tony, but I disagree that "transient" addresses 
> the issue at hand. The challenge being made is that, as Gwendal puts it, it's 
> _unwise_ to have a default implementation, because people might forget that 
> there is a default implementation. "Transient" only works if you remember 
> that there is a default implementation, and in that case, we already have a 
> clear syntax for overriding the default.
> 
> Right—I hope it hasn't sounded like I'm conflating the two concepts 
> completely. The reason I brought up "transient" is because nearly all of the 
> "risky" examples being cited so far have been of the variety "I have a type 
> where some properties happen to be Equatable but shouldn't be involved in 
> equality", so my intention has been to show that if we have a better solution 
> to that specific problem (which is, related to but not the same as the 
> question at hand), then there aren't enough risky cases left to warrant 
> adding this level of complexity to the protocol system.
>  
> 
> As others point out, there's a temptation here to write things like 
> "transient(Equatable)" so as to control the synthesis of implementations on a 
> per-protocol basis. By that point, you've invented a whole new syntax for 
> implementing protocol requirements. (Ah, you might say, but it's hard to 
> write a good hashValue implementation: sure, but that's adequately solved by 
> a library-supplied combineHashes() function.)
> 
> I totally agree with this. A design that would try to annotate "transient" 
> with a protocol or list of protocols is missing the point of the semantics 
> that "transient" is supposed to provide. It's not a series of switches to 
> that can be flipped on and off for arbitrary protocols—it's a semantic tag 
> that assigns additional meaning to properties and certain protocols (such as 
> Equatable, Hashable, and Codable, but possibly others that haven't been 
> designed yet) would have protocol-specific behavior for those properties.
> 
> To better explain what I've been poking at, I'm kind of extrapolating this 
> out to a possible future where it may be possible to more generally (1) 
> define custom @attributes in Swift, like Java annotations, and then (2) use 
> some metaprogramming constructs to generate introspective default 
> implementations for a protocol at compile-time just as the compiler does 
> "magically" now, and the generator would be able to query attributes that are 
> defined by the same library author as the protocol and handle them 
> accordingly.
> 
> In a world where that's possible, I think it's less helpful to think in terms 
> of "I need to distinguish between conforming to X and getting a synthesized 
> implementation and conforming to X and avoiding the synthesized 
> implementation because the default might be risky", but instead to think in 
> terms of "How can I provide enough semantic information about my types to 
> remove the risk?"
> 
> In other words, the switches we offer developers to flip shouldn't be about 
> turning on/off entire features, but about giving the compiler enough 
> information to make it smart enough that we never need to turn it off in the 
> first place. As I alluded to before, if I have 10 properties in a type and 
> only 1 of those needs to be ignored in ==/hashValue/whatever, writing 
> "Equatable" instead of "derives Equatable" isn't all that helpful. Yes, it 
> spits out an error message where there wouldn't have been one, but it doesn't 
> reduce any of the burden of having to provide the appropriate manual 
> implementation.

Speaking of which, what do you suppose the hit/miss ratio would be WRT 
synthesized `Equatable`, etc, if we introduced "trivial" or "simple" types 
("trivial struct Foo {}", "trivial class Bar {}") -- meaning that all the 
stored properties (or associated values, for enums) are either all trivial 
value types or trivial reference types -- and only performing the code code 
synthesis for such trivial types? We'd probably need some mechanism of telling 
the compiler that for this purpose, a struct counts as a reference type (or the 
other way around)... mostly I'm thinking that the Unsafe*Pointer types would 
break the semantic contract, since they kinda have both (from a certain point 
of view).

trivial struct Foo : Equatable { // both x and y are value semantics all the 
way down, so "==" can be synthesized
 var x: Int
 var y: Int
}
struct FooWithHistory : Equatable { // Arrays use references under the covers; 
this can't be `trivial`, nothing is synthesized, and this wouldn't compile 
without the user supplying a `==` function
  var x: Int { didSet { xHistory.append(oldValue) } }
  var y: Int { didSet { yHistory.append(oldValue) } }
  var xHistory: [Int] = []
  var yHistory: [Int] = []
}

(I tried to come up with a simple example that was all references "all the way 
down", but you've eventually gotta answer the question "a reference to what?", 
at which point the type could no longer be "trivial", so I'm not sure that's 
possible, at least in a useful manner. I suppose maybe the "bottom" property 
could be a pointer... that might do it...)

It seems to me that there might be implications here for auto-parallelization, 
too. If so, this would be a great time in Swift's evolution (😃) to explore the 
idea.

- Dave Sweeris
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to