> 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
