Reviews are an important part of the Swift evolution process. All review feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to the review manager via the forum messaging feature. When contacting the review manager directly, please keep the proposal link at the top of the message.
What goes into a review?
The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:
What is your evaluation of the proposal?
Is the problem being addressed significant enough to warrant a change to Swift?
Does this proposal fit well with the feel and direction of Swift?
If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
More information about the Swift evolution process is available here.
As the latest proposal related to dynamic member lookup, I think there should be a future direction for some type of static member lookup that guarantees optimal performance (no penalties from key paths) and that is available in embedded swift.
Just for clarification: by "future direction", do you mean that there should be a general discussion about this, or do you mean that you would expect the proposal to include a "Future Directions" section with more information? If the latter, do you mind elaborating on how you see this topic fitting in with the proposal, and what sort of information you'd expect the proposal to contain on it?
Thanks for the reply! I just mean a section in the proposal acknowledging the potential need for static (rather than dynamic) member lookup. It seems like the static lookup feature was shoehorned into dynamicMemberLookup+key paths. So now that dynamic member lookup is pretty much feature-complete, I think we should start discussing a static lookup approach. Don’t get me wrong, key-path-based lookup works great and is often optimized by the compiler. However, that’s precisely the problem: key-path lookup is only optimized so performance isn’t guaranteed. Consequently, environments like Embedded Swift where key paths are unavailable due to strict performance requirements needlessly miss out on this very useful feature.
It seems like the reason key-path based dynamic member lookup exists in the first place is because string-based dynamic lookup predates it. Thus, string-based dynamic member lookup was simply extended to support key paths. That’s mostly worked fine, but nowadays Embedded Swift underscores the need for a lookup feature that guarantees minimal overhead. Perhaps, we could have a built-in macro/attribute that we attach to a property and that tells the compiler to expose members of that property in self. Of course, I don’t want to derail the discussion so we don’t need to flesh out all the details here. It just seems appropriate to simply recognize the future need for static lookup in the proposal.
Got it — thanks for explaining! To be honest, I'm not sure this specific proposal would be the best place for that sort of acknowledgement; proposals are typically self-contained, and I'd expect "Future Directions" here to detail what else we can do with dynamic member lookup arguments specifically, rather than the feature as a whole as part of a much larger discussion. Long-term feature arcs are likely best captured as vision documents instead.
Though, I do think that discussion is worth having in general, separately!
Aside
I haven't thought this through, but I do think it'd be straightforward to pitch a special form of dynamic member lookups as being referentially transparent so that you do effectively get static lookup as a guaranteed part of dynamic member lookup, without needing additional macros or annotations — e.g., if you have
@dynamicMemberLookup
struct S {
let inner: Inner
subscript<T>(dynamicMember member: KeyPath<Inner, T>) -> T {
inner[keyPath: member]
}
}
let s = S(...)
s.foo
the compiler could inspect the body of subscript(dynamicMember:) and see it has a special form that's just forwarding to another member reference; instead of translating s.foo into s[dynamicMember: \Inner.foo], it could instead syntactically transform it into s.inner.foo at the AST level (possibly with special "punch-throughs" to ignore access control considerations) — then the "optimization" aspect is guaranteed to occur at a much higher level than the optimizer itself.
In any case, this sort of exploration seems reasonable to do separately.
This proposal is a completely reasonable extension. Probably should have worked this way all the time, because defaulted arguments are useful for passing through caller-side information.
Taking off my reviewer hat, I would agree with the proposal that the overload resolution changes here are, in practice, likely to be so implausible as to not be source-breaking.
But I would go further that any extant implementation of subscript(dynamicMember:...:)—if one exists—that currently isn't ever called via dynamic member lookup is probably buggy code, an expression of authorial intention that just isn't being honored and will be with this proposal.