> On Apr 6, 2017, at 4:22 PM, Joe Groff <[email protected]> wrote:
> 
>> 
>> On Apr 6, 2017, at 2:15 PM, Matthew Johnson <[email protected]> wrote:
>> 
>> 
>>> On Apr 6, 2017, at 1:11 PM, Joe Groff <[email protected]> wrote:
>>> 
>>> 
>>>> On Apr 6, 2017, at 11:06 AM, John McCall <[email protected]> wrote:
>>>> 
>>>>> On Apr 6, 2017, at 1:41 PM, Matthew Johnson <[email protected]> 
>>>>> wrote:
>>>>>> On Apr 6, 2017, at 12:32 PM, John McCall <[email protected]> wrote:
>>>>>> 
>>>>>>> On Apr 5, 2017, at 9:46 PM, Matthew Johnson via swift-evolution 
>>>>>>> <[email protected]> wrote:
>>>>>>>> On Apr 5, 2017, at 7:32 PM, David Smith via swift-evolution 
>>>>>>>> <[email protected]> wrote:
>>>>>>>> 
>>>>>>>> The rationale for using the same syntax is that a KeyPath is an 
>>>>>>>> unapplied property/subscript access. Even the multi-segment part of it 
>>>>>>>> isn't necessarily dissimilar: I don't think it would be unreasonable 
>>>>>>>> to imagine that \Foo.someMethod.someOtherMethod could work*, that'd 
>>>>>>>> just be function composition after all.
>>>>>>>> 
>>>>>>>> KeyPath : Properties/Subscripts :: Functions with a self argument : 
>>>>>>>> Methods
>>>>>>>> 
>>>>>>>>        David
>>>>>>>> 
>>>>>>>> *not proposing this, haven't thought carefully about whether there are 
>>>>>>>> edge cases I'm missing here, but I think the analogy holds
>>>>>>> 
>>>>>>> I alluded to this kind of thing in the earlier threads.  It would be 
>>>>>>> very cool to see this explored in the future.
>>>>>>> 
>>>>>>> I really like the latest draft and am eagerly anticipating Smart 
>>>>>>> KeyPaths being implemented.  Thank you for listening to feedback from 
>>>>>>> the community!
>>>>>>> 
>>>>>>> One possible future direction I have been wondering about is whether it 
>>>>>>> might be interesting to expose an anonymous type for each distinct key 
>>>>>>> path which would have static members for getting (and setting if 
>>>>>>> mutable) the value.  The types would inherit from the most specific 
>>>>>>> matching key path type included in this proposal.  This would allow us 
>>>>>>> pass key paths statically using the type system and therefore not 
>>>>>>> requiring any runtime overhead.  
>>>>>>> 
>>>>>>> I have experimented with this approach in some of my own code and it 
>>>>>>> looks like it would be a very promising approach aside from the 
>>>>>>> boilerplate required to write these types manually.  I have abandoned 
>>>>>>> this approach for now because of the boilerplate and because the 
>>>>>>> syntactic sugar of the key path shorthand in this proposal is too 
>>>>>>> attractive to pass up.  I would love to explore it again in the future 
>>>>>>> if key paths were to support this approach.
>>>>>> 
>>>>>> Our generics system does not require generic code to be de-genericized 
>>>>>> ("instantiated" in C++ terminology, "monomorphized" in Rust, etc.) in 
>>>>>> order to be run.  The generic code for applying a value of an unknown 
>>>>>> key-path type would look exactly like the non-generic code for applying 
>>>>>> a dynamic key-path type.  To get a runtime benefit, the compiler would 
>>>>>> have to de-genericize all the code between the function that formed the 
>>>>>> concrete key path and the function that applied it.  If the compiler can 
>>>>>> do that, it can also specialize that code for a known key path argument, 
>>>>>> the same way that it can specialize a function for a known function 
>>>>>> argument.  So there's no point.
>>>>> 
>>>>> Thanks for the reply John.  There may not be any additional optimization 
>>>>> opportunities in terms of code generation when using the key path but 
>>>>> wouldn’t it save on storage and reference counting related to key path 
>>>>> value?
>>>> 
>>>> If you're specializing all the way down, any sort of boxing should be 
>>>> possible to eliminate as well.
>>>> 
>>>> If you mean in unspecialized code, well, I'm not entirely sure what 
>>>> representation Joe is using, but I would assume that the fast path — where 
>>>> a key path doesn't capture anything — does not require any allocation.  In 
>>>> that sense, there's a strong parallel with how we represent functions: 
>>>> yes, avoiding an extra allocation would be nice, but if you're willing to 
>>>> accept an occasional allocation in more complex cases, there are also a 
>>>> lot of benefits from being able to always give the type a concrete, 
>>>> fixed-size representation.
>>> 
>>> Yeah, I've set up the implementation so that literal key paths get emitted 
>>> as global objects that don't need allocation, and shouldn't need 
>>> refcounting once the runtime gains support for inert objects. I also set up 
>>> the SIL representation for these in a way that we'll eventually be able to 
>>> do high-level optimization, so that when we see a literal key path applied 
>>> to a concrete base, we can lower the key path application into direct 
>>> projections on the base value. Since everything is implemented using opaque 
>>> classes now, there isn't much opportunity for specialization, but I think 
>>> high-level optimizations are probably a better fit for the common cases.
>> 
>> If I understand this correctly the storage for key path values that begin as 
>> a literal would be a non-refcounted word after inert object support is 
>> included in the runtime.  Is that correct?
> 
> The value representation will a pointer, the same as any class type, though 
> we can avoid dynamically allocating space for it if it isn't parameterized at 
> all. Information about the key path's contents has to live in the process 
> somewhere.

Can you clarify what you mean by “if it isn’t parameterized at all”?

> 
>> Can you elaborate on the high-level optimizations you have in mind?
> 
> If you end up with 'x[keyPath: \.y]', whether directly or by constant 
> propagation, the compiler ought to be able to optimize that down to 'x.y’.

That makes sense.  Of course they won’t often be used like this - why not just 
write `x.y` in the first place? 

> 
>> Also, you said "Since everything is implemented using opaque classes now, 
>> there isn't much opportunity for specialization”.  Does that mean the 
>> implementation may change in the future in a way that might allow for more 
>> opportunity for specialization?
> 
> A design using generalized existentials would be a lot more expressive and 
> probably be able to exercise the compiler's generic optimization 
> infrastructure better.
> 
> -Joe

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to