SE-0249: Key Path Expressions as Functions

+1

Nice addition to the language.

  • What is your evaluation of the proposal?
    +1

  • Is the problem being addressed significant enough to warrant a change to Swift?
    Yes

  • Does this proposal fit well with the feel and direction of Swift?
    Yes

  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
    I've used custom operators like ^ to implement this functionality. That always generates team debate about the introduction of operators. Also used functions instead of operators. Much prefer the native support for this behavior as described in the proposal.

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
    Read the proposal. Have some experience with alternate solutions.

2 Likes
  • What is your evaluation of the proposal?
    +1! It's a nice to have thing that warms my heart. I hate typing $0, it's such an awkward key combination
  • Is the problem being addressed significant enough to warrant a change to Swift?
    While the world would be okay without this feature, I think it's still worth adding.
  • Does this proposal fit well with the feel and direction of Swift?
    Yep! I feel like swift is all about reusing literals for many similar things, and while this isn't ExpressibleByKeyPathLiteral it feels like it.
  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
    n/a
  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
    I've read the pitch thread and the proposal

+1, enables a nicer and more clear way to express higher order computation across data structures.

My only concern is whether this will cause compile time issues in the type checker due to the addition of new implicit conversions. I think the risk of this in practice is low though, because it only affects expressions that have keypath literals in them, which are comparatively rare.

Unclear to me, I'm neutral on this. This is literally saving one character (assuming the use of a ^ operator like in the alternatives section), so it is hard to argue that this is critical. That said, we don't have that operator standardized.

Yes.

No, n/a

I read the proposal in detail, but haven't followed the other discussions closely.

-Chris

1 Like
  • What is your evaluation of the proposal?
    +1 This something we need, especially if Type.mutatingMethod is never going to be made to return an (inout Type, Arguments...) -> Result function.
  • Is the problem being addressed significant enough to warrant a change to Swift?
    Yes.
  • Does this proposal fit well with the feel and direction of Swift?
    Yes.
  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
    N/A
  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
    I read the proposal, and have been following previous discussion of the issue since it was first brought up as an alternative to implementing SE-402.
  • What is your evaluation of the proposal?
    I think this would cause confusion unless it also address tuples. If that is the case then that should cut the surface area of tuples which can help us get closer a 0110 being implemented.
    https://github.com/apple/swift-evolution/blob/master/proposals/0110-distingish-single-tuple-arg.md

  • Is the problem being addressed significant enough to warrant a change to Swift?
    Not by itself I am afraid. If I am able to use KeyPath notation in this way I would be confused by it as new user.

Look at the reasoning for reverting 0110 it was mostly due to closures which this proposal should address.

https://lists.swift.org/pipermail/swift-evolution-announce/2017-June/000386.html

Edit:

  let pairs = [(1, "A"), (2, "B")]
  print(pairs.map { $0.0 })

I am saying that this is a great feature but it needs to include tupples KeyPath otherwise it will cause confusion.

Can you explain what you mean by this? Key path literals, as converted in this proposal, are one-argument functions, so I'm not sure how SE-0110 applies.

Strong +1.

It is reasonable.

Yes!

NA.

Read the pitch and the proposal.

  let pairs = [(1, "A"), (2, "B")]
  print(pairs.map { $0.0 })

+1 will be a great addition to Swift.

Tuple key paths were recently added, so your example becomes:

let pairs = [(1, "A"), (2, "B")]
print(pairs.map(\.0))

Does this address your concern?

2 Likes

Is there a tool chain to test this? Can you add the tuple clarification to the proposal? $0.0 should equal \.0.0 that is why I think proposal 110 is relavant here.
There is a chance that this proposal would address all the concerns that got 110 reverted.

The commit that you called out does not mean SE-0110 was reverted, and having a new syntax to do something doesn't mean we get to break the old syntax. I don't see how it's relevant to the discussion.

Are KeyPath Expressions as Functions able to distinguish between single tuple arguments as proposed and accepted in 110?

I feel like Thanos right now, am I the only one who sees this? I guess part of it it’s because I have not used tuple keypaths so it is not apparent how this new feature is going to interact with it.

Key paths always convert to functions that take exactly one argument. So yes, the map Stephen wrote should work (not the one you wrote). I guess someone should make sure that this fails, but I don't see why it wouldn't.

func foo(_ fn: (Int, Int) -> Int) {
  print(fn(1, 2))
}
foo(\.0)

+1

  • Is the problem being addressed significant enough to warrant a change to Swift?

Yes

  • Does this proposal fit well with the feel and direction of Swift?

Yes

  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

N/A

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

A quick reading

I use exactly the same syntax as in the proposal, implemented as map and filter extensions. We should admit that it's not much different than the closure syntax though much more limited. I don't mind using it, but since it's just sugar it's worth making it as sweet as possible! The proposed implementation implicitly converts a key path to a closure, so why should it not be a trailing closure? I suggest to allow parentheses to be skipped:

users.map\.email
users.filter\.isAdmin

or

users.map \.email
users.filter \.isAdmin

Toolchains! Fresh toolchains for macOS and Linux! Get 'em while they're hot!

(My review: I think this syntax is an excellent idea and will definitely become part of my personal style. I hope testing doesn't turn up any showstoppers.)

8 Likes

This is not correct, it has been mentioned before, this proposal only lets you convert a function with one parameter to a keypath. That implies that there never will be $1 (except for the yet undecided WritableKeyPath which is not part of the proposal), or in other words \. already refers to Root / $0 argument and in case of a tuple \.0 is already KeyPath<Root, FirstTupleElem>.

1 Like

The problem here is you lose the ability to chain along:

users.filter(\.isAdmin).map(\.email)
users.filter\.isAdmin // ???

Line breaks could help here, but it'd be a lot of special casing to worry about.

4 Likes