[Returned for revision] SE-0161: Smart KeyPaths: Better Key-Value Coding for Swift

Proposal Link: swift-evolution/0161-key-paths.md at master · apple/swift-evolution · GitHub

Hello Swift community,

The review of SE-0161 “Smart KeyPaths: Better Key-Value Coding for Swift” ran from March 30...April 5, 2017. The proposal was very well-received *except* that reviewers felt that the #keyPath syntax was far too heavy for this new language construct, and preferred the lighter-weight syntax of the pre-review drafts. This proposal is returned for revision to address the syntax.

The heavyweight #keyPath syntax was requested by the core team after reviewing earlier drafts, which used a far lighter syntax:

  // (Rejected) syntax from pre-review drafts
  let firstFriendsNameKeyPath = Person.friends[0].name
  print(luke[keyPath: .friends[0].name])

The core team’s specific concern was that these key path expressions (e.g., Person.friends[0].name) don’t make it sufficiently clear that the actual property accesses are being delayed, and that the contextual cues (“Person." vs. “luke.”) are insufficient to disambiguate for the human reader. Hence, the request for a different (more explicit) syntax.

Reviewers rightly point out that it is natural for key-paths to use the same syntax as unapplied instance method references, e.g., Person.someInstanceMethod produces a value of some function type with the “Self” type curried, e.g., (Person) -> (param-types) -> result-type. The core team agrees with this sentiment. The core team also felt that Swift’s existing unapplied method references suffer from the same clarity problems as the initial key-path syntax, i.e., that it isn’t sufficiently clear that the actual application of “self” is being delayed.

The core team has a specific proposal: use the backslash (‘\’) to as a leading indicator for key paths. Specifically,

  // Proposed syntax for second revision
  let firstFriendsNameKeyPath = \Person.friends[0].name
  print(luke[keyPath: \.friends[0].name])

The backslash is a visual cue that the actual application of this chain of property references is delayed, eliminating ambiguities, yet is still quite lightweight and feels “first-class” in the language.

The core team felt that, in the future, the backslash should also be used for unapplied instance method references, to match the proposed syntax for key paths and improve clarity for this non obvious feature. This change could be staged in as a revision to the accepted-but-never-implemented SE-0042: Flattening the function type of unapplied method references <https://github.com/apple/swift-evolution/blob/master/proposals/0042-flatten-method-types.md&gt;, e.g.,

  // Proposed future syntax for unapplied instance method references
        class Person {
    func instanceMethod(_: String) -> Int { … }
  }

  let f1 = Person.instanceMethod // to-be-deprecated; produces a value of type (Person) -> (String) -> Int
  let f2 = \Person.instanceMethod // to-be-introduced via a revised SE-0042: produces a value of type (Person, String) -> Int

Such an approach gives us a way to stage in SE-0042 and get to eventual consistency between key paths and unapplied instance method references.

  - Doug
  Review Manager

Works for me. +1

···

On Apr 5, 2017, at 4:01 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Proposal Link: https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md

Hello Swift community,

The review of SE-0161 “Smart KeyPaths: Better Key-Value Coding for Swift” ran from March 30...April 5, 2017. The proposal was very well-received *except* that reviewers felt that the keypath syntax was far too heavy for this new language construct, and preferred the lighter-weight syntax of the pre-review drafts. This proposal is returned for revision to address the syntax.

The heavyweight keypath syntax was requested by the core team after reviewing earlier drafts, which used a far lighter syntax:

  // (Rejected) syntax from pre-review drafts
  let firstFriendsNameKeyPath = Person.friends[0].name
  print(luke[keyPath: .friends[0].name])

The core team’s specific concern was that these key path expressions (e.g., Person.friends[0].name) don’t make it sufficiently clear that the actual property accesses are being delayed, and that the contextual cues (“Person." vs. “luke.”) are insufficient to disambiguate for the human reader. Hence, the request for a different (more explicit) syntax.

Reviewers rightly point out that it is natural for key-paths to use the same syntax as unapplied instance method references, e.g., Person.someInstanceMethod produces a value of some function type with the “Self” type curried, e.g., (Person) -> (param-types) -> result-type. The core team agrees with this sentiment. The core team also felt that Swift’s existing unapplied method references suffer from the same clarity problems as the initial key-path syntax, i.e., that it isn’t sufficiently clear that the actual application of “self” is being delayed.

The core team has a specific proposal: use the backslash (‘\’) to as a leading indicator for key paths. Specifically,

  // Proposed syntax for second revision
  let firstFriendsNameKeyPath = \Person.friends[0].name
  print(luke[keyPath: \.friends[0].name])

The backslash is a visual cue that the actual application of this chain of property references is delayed, eliminating ambiguities, yet is still quite lightweight and feels “first-class” in the language.

The core team felt that, in the future, the backslash should also be used for unapplied instance method references, to match the proposed syntax for key paths and improve clarity for this non obvious feature. This change could be staged in as a revision to the accepted-but-never-implemented SE-0042: Flattening the function type of unapplied method references <https://github.com/apple/swift-evolution/blob/master/proposals/0042-flatten-method-types.md&gt;, e.g.,

  // Proposed future syntax for unapplied instance method references
        class Person {
    func instanceMethod(_: String) -> Int { … }
  }

  let f1 = Person.instanceMethod // to-be-deprecated; produces a value of type (Person) -> (String) -> Int
  let f2 = \Person.instanceMethod // to-be-introduced via a revised SE-0042: produces a value of type (Person, String) -> Int

Such an approach gives us a way to stage in SE-0042 and get to eventual consistency between key paths and unapplied instance method references.

  - Doug
  Review Manager

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

Proposal Link: https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md

Hello Swift community,

The review of SE-0161 “Smart KeyPaths: Better Key-Value Coding for Swift” ran from March 30...April 5, 2017. The proposal was very well-received *except* that reviewers felt that the keypath syntax was far too heavy for this new language construct, and preferred the lighter-weight syntax of the pre-review drafts. This proposal is returned for revision to address the syntax.

The heavyweight keypath syntax was requested by the core team after reviewing earlier drafts, which used a far lighter syntax:

  // (Rejected) syntax from pre-review drafts
  let firstFriendsNameKeyPath = Person.friends[0].name
  print(luke[keyPath: .friends[0].name])

The core team’s specific concern was that these key path expressions (e.g., Person.friends[0].name) don’t make it sufficiently clear that the actual property accesses are being delayed, and that the contextual cues (“Person." vs. “luke.”) are insufficient to disambiguate for the human reader. Hence, the request for a different (more explicit) syntax.

Reviewers rightly point out that it is natural for key-paths to use the same syntax as unapplied instance method references, e.g., Person.someInstanceMethod produces a value of some function type with the “Self” type curried, e.g., (Person) -> (param-types) -> result-type. The core team agrees with this sentiment. The core team also felt that Swift’s existing unapplied method references suffer from the same clarity problems as the initial key-path syntax, i.e., that it isn’t sufficiently clear that the actual application of “self” is being delayed.

The core team has a specific proposal: use the backslash (‘\’) to as a leading indicator for key paths. Specifically,

  // Proposed syntax for second revision
  let firstFriendsNameKeyPath = \Person.friends[0].name
  print(luke[keyPath: \.friends[0].name])

The backslash is a visual cue that the actual application of this chain of property references is delayed, eliminating ambiguities, yet is still quite lightweight and feels “first-class” in the language.

The core team felt that, in the future, the backslash should also be used for unapplied instance method references, to match the proposed syntax for key paths and improve clarity for this non obvious feature. This change could be staged in as a revision to the accepted-but-never-implemented SE-0042: Flattening the function type of unapplied method references <https://github.com/apple/swift-evolution/blob/master/proposals/0042-flatten-method-types.md&gt;, e.g.,

  // Proposed future syntax for unapplied instance method references
        class Person {
    func instanceMethod(_: String) -> Int { … }
  }

  let f1 = Person.instanceMethod // to-be-deprecated; produces a value of type (Person) -> (String) -> Int
  let f2 = \Person.instanceMethod // to-be-introduced via a revised SE-0042: produces a value of type (Person, String) -> Int

Such an approach gives us a way to stage in SE-0042 and get to eventual consistency between key paths and unapplied instance method references.

+1000. This is excellent news! I have been looking forward to seeing SE-0042 implemented.

···

On Apr 5, 2017, at 6:01 PM, Douglas Gregor <dgregor@apple.com> wrote:

  - Doug
  Review Manager

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

+Int.max. Let’s do this thing!

···

On Apr 5, 2017, at 4:01 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Proposal Link: https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md

Hello Swift community,

The review of SE-0161 “Smart KeyPaths: Better Key-Value Coding for Swift” ran from March 30...April 5, 2017. The proposal was very well-received *except* that reviewers felt that the keypath syntax was far too heavy for this new language construct, and preferred the lighter-weight syntax of the pre-review drafts. This proposal is returned for revision to address the syntax.

The heavyweight keypath syntax was requested by the core team after reviewing earlier drafts, which used a far lighter syntax:

  // (Rejected) syntax from pre-review drafts
  let firstFriendsNameKeyPath = Person.friends[0].name
  print(luke[keyPath: .friends[0].name])

The core team’s specific concern was that these key path expressions (e.g., Person.friends[0].name) don’t make it sufficiently clear that the actual property accesses are being delayed, and that the contextual cues (“Person." vs. “luke.”) are insufficient to disambiguate for the human reader. Hence, the request for a different (more explicit) syntax.

Reviewers rightly point out that it is natural for key-paths to use the same syntax as unapplied instance method references, e.g., Person.someInstanceMethod produces a value of some function type with the “Self” type curried, e.g., (Person) -> (param-types) -> result-type. The core team agrees with this sentiment. The core team also felt that Swift’s existing unapplied method references suffer from the same clarity problems as the initial key-path syntax, i.e., that it isn’t sufficiently clear that the actual application of “self” is being delayed.

The core team has a specific proposal: use the backslash (‘\’) to as a leading indicator for key paths. Specifically,

  // Proposed syntax for second revision
  let firstFriendsNameKeyPath = \Person.friends[0].name
  print(luke[keyPath: \.friends[0].name])

The backslash is a visual cue that the actual application of this chain of property references is delayed, eliminating ambiguities, yet is still quite lightweight and feels “first-class” in the language.

The core team felt that, in the future, the backslash should also be used for unapplied instance method references, to match the proposed syntax for key paths and improve clarity for this non obvious feature. This change could be staged in as a revision to the accepted-but-never-implemented SE-0042: Flattening the function type of unapplied method references <https://github.com/apple/swift-evolution/blob/master/proposals/0042-flatten-method-types.md&gt;, e.g.,

  // Proposed future syntax for unapplied instance method references
        class Person {
    func instanceMethod(_: String) -> Int { … }
  }

  let f1 = Person.instanceMethod // to-be-deprecated; produces a value of type (Person) -> (String) -> Int
  let f2 = \Person.instanceMethod // to-be-introduced via a revised SE-0042: produces a value of type (Person, String) -> Int

Such an approach gives us a way to stage in SE-0042 and get to eventual consistency between key paths and unapplied instance method references.

  - Doug
  Review Manager

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

+1

This is much better than keypath(Root, .path).

I think I can get used to using the escape \ character. I'll think of it as escaping execution of the key path.

···

On Apr 5, 2017, at 7:01 PM, Douglas Gregor <dgregor@apple.com> wrote:

Proposal Link: https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md

Hello Swift community,

The review of SE-0161 “Smart KeyPaths: Better Key-Value Coding for Swift” ran from March 30...April 5, 2017. The proposal was very well-received *except* that reviewers felt that the keypath syntax was far too heavy for this new language construct, and preferred the lighter-weight syntax of the pre-review drafts. This proposal is returned for revision to address the syntax.

The heavyweight keypath syntax was requested by the core team after reviewing earlier drafts, which used a far lighter syntax:

  // (Rejected) syntax from pre-review drafts
  let firstFriendsNameKeyPath = Person.friends[0].name
  print(luke[keyPath: .friends[0].name])

The core team’s specific concern was that these key path expressions (e.g., Person.friends[0].name) don’t make it sufficiently clear that the actual property accesses are being delayed, and that the contextual cues (“Person." vs. “luke.”) are insufficient to disambiguate for the human reader. Hence, the request for a different (more explicit) syntax.

Reviewers rightly point out that it is natural for key-paths to use the same syntax as unapplied instance method references, e.g., Person.someInstanceMethod produces a value of some function type with the “Self” type curried, e.g., (Person) -> (param-types) -> result-type. The core team agrees with this sentiment. The core team also felt that Swift’s existing unapplied method references suffer from the same clarity problems as the initial key-path syntax, i.e., that it isn’t sufficiently clear that the actual application of “self” is being delayed.

The core team has a specific proposal: use the backslash (‘\’) to as a leading indicator for key paths. Specifically,

  // Proposed syntax for second revision
  let firstFriendsNameKeyPath = \Person.friends[0].name
  print(luke[keyPath: \.friends[0].name])

The backslash is a visual cue that the actual application of this chain of property references is delayed, eliminating ambiguities, yet is still quite lightweight and feels “first-class” in the language.

The core team felt that, in the future, the backslash should also be used for unapplied instance method references, to match the proposed syntax for key paths and improve clarity for this non obvious feature. This change could be staged in as a revision to the accepted-but-never-implemented SE-0042: Flattening the function type of unapplied method references <https://github.com/apple/swift-evolution/blob/master/proposals/0042-flatten-method-types.md&gt;, e.g.,

  // Proposed future syntax for unapplied instance method references
        class Person {
    func instanceMethod(_: String) -> Int { … }
  }

  let f1 = Person.instanceMethod // to-be-deprecated; produces a value of type (Person) -> (String) -> Int
  let f2 = \Person.instanceMethod // to-be-introduced via a revised SE-0042: produces a value of type (Person, String) -> Int

Such an approach gives us a way to stage in SE-0042 and get to eventual consistency between key paths and unapplied instance method references.

  - Doug
  Review Manager

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

+1. This looks fantastic.

Charles

···

On Apr 5, 2017, at 6:01 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Proposal Link: https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md

Hello Swift community,

The review of SE-0161 “Smart KeyPaths: Better Key-Value Coding for Swift” ran from March 30...April 5, 2017. The proposal was very well-received *except* that reviewers felt that the keypath syntax was far too heavy for this new language construct, and preferred the lighter-weight syntax of the pre-review drafts. This proposal is returned for revision to address the syntax.

The heavyweight keypath syntax was requested by the core team after reviewing earlier drafts, which used a far lighter syntax:

  // (Rejected) syntax from pre-review drafts
  let firstFriendsNameKeyPath = Person.friends[0].name
  print(luke[keyPath: .friends[0].name])

The core team’s specific concern was that these key path expressions (e.g., Person.friends[0].name) don’t make it sufficiently clear that the actual property accesses are being delayed, and that the contextual cues (“Person." vs. “luke.”) are insufficient to disambiguate for the human reader. Hence, the request for a different (more explicit) syntax.

Reviewers rightly point out that it is natural for key-paths to use the same syntax as unapplied instance method references, e.g., Person.someInstanceMethod produces a value of some function type with the “Self” type curried, e.g., (Person) -> (param-types) -> result-type. The core team agrees with this sentiment. The core team also felt that Swift’s existing unapplied method references suffer from the same clarity problems as the initial key-path syntax, i.e., that it isn’t sufficiently clear that the actual application of “self” is being delayed.

The core team has a specific proposal: use the backslash (‘\’) to as a leading indicator for key paths. Specifically,

  // Proposed syntax for second revision
  let firstFriendsNameKeyPath = \Person.friends[0].name
  print(luke[keyPath: \.friends[0].name])

The backslash is a visual cue that the actual application of this chain of property references is delayed, eliminating ambiguities, yet is still quite lightweight and feels “first-class” in the language.

The core team felt that, in the future, the backslash should also be used for unapplied instance method references, to match the proposed syntax for key paths and improve clarity for this non obvious feature. This change could be staged in as a revision to the accepted-but-never-implemented SE-0042: Flattening the function type of unapplied method references <https://github.com/apple/swift-evolution/blob/master/proposals/0042-flatten-method-types.md&gt;, e.g.,

  // Proposed future syntax for unapplied instance method references
        class Person {
    func instanceMethod(_: String) -> Int { … }
  }

  let f1 = Person.instanceMethod // to-be-deprecated; produces a value of type (Person) -> (String) -> Int
  let f2 = \Person.instanceMethod // to-be-introduced via a revised SE-0042: produces a value of type (Person, String) -> Int

Such an approach gives us a way to stage in SE-0042 and get to eventual consistency between key paths and unapplied instance method references.

  - Doug
  Review Manager

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

Is the choice of backslash up for review? I think another operator, perhaps
backtick (`), would work better. My concern is with the \() escaping syntax
within strings, which has the opposite behavior wrt. execution time:

let untrue = "2 + 2 = \((5, print("inside")).0)"
print("outside")
print(untrue)
// output:
// "inside"
// "outside"
// "2 + 2 = 5"

If the purpose of the backslash syntax is to make the delayed execution
time clear, I don't believe it achieves that goal.

Love the proposal otherwise, and I for sure see the logic in making
Person.instanceMethod "look different" from Person.classOrStaticProperty.

-Colin

···

On Wed, Apr 5, 2017 at 7:01 PM Douglas Gregor via swift-evolution < swift-evolution@swift.org> wrote:

Proposal Link:
https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md

Hello Swift community,

The review of SE-0161 “Smart KeyPaths: Better Key-Value Coding for Swift”
ran from March 30...April 5, 2017. The proposal was very well-received
*except* that reviewers felt that the keypath syntax was far too heavy
for this new language construct, and preferred the lighter-weight syntax of
the pre-review drafts. This proposal is *returned for revision* to
address the syntax.

The heavyweight keypath syntax was requested by the core team after
reviewing earlier drafts, which used a far lighter syntax:

// (Rejected) syntax from pre-review drafts
let firstFriendsNameKeyPath = Person.friends[0].name
print(luke[keyPath: .friends[0].name])

The core team’s specific concern was that these key path expressions
(e.g., Person.friends[0].name) don’t make it sufficiently clear that the
actual property accesses are being delayed, and that the contextual cues (“
Person." vs. “luke.”) are insufficient to disambiguate for the human
reader. Hence, the request for a different (more explicit) syntax.

Reviewers rightly point out that it is natural for key-paths to use the
same syntax as unapplied instance method references, e.g.,
Person.someInstanceMethod produces a value of some function type with the
“Self” type curried, e.g., (Person) -> (param-types) -> result-type. The
core team agrees with this sentiment. The core team also felt that Swift’s
existing unapplied method references suffer from the same clarity problems
as the initial key-path syntax, i.e., that it isn’t sufficiently clear that
the actual application of “self” is being delayed.

The core team has a specific proposal: use the backslash (‘\’) to as a
leading indicator for key paths. Specifically,

// Proposed syntax for second revision
let firstFriendsNameKeyPath = \Person.friends[0].name
print(luke[keyPath: \.friends[0].name])

The backslash is a visual cue that the actual application of this chain of
property references is delayed, eliminating ambiguities, yet is still quite
lightweight and feels “first-class” in the language.

The core team felt that, in the future, the backslash should also be used
for unapplied instance method references, to match the proposed syntax for
key paths and improve clarity for this non obvious feature. This change
could be staged in as a revision to the accepted-but-never-implemented SE-0042:
Flattening the function type of unapplied method references
<https://github.com/apple/swift-evolution/blob/master/proposals/0042-flatten-method-types.md&gt;,
e.g.,

// Proposed future syntax for unapplied instance method references
        class Person {
  func instanceMethod(_: String) -> Int { … }
}

let f1 = Person.instanceMethod // to-be-deprecated; produces a value of
type (Person) -> (String) -> Int
let f2 = \Person.instanceMethod // to-be-introduced via a revised
SE-0042: produces a value of type (Person, String) -> Int

Such an approach gives us a way to stage in SE-0042 and get to eventual
consistency between key paths and unapplied instance method references.

- Doug
Review Manager

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

+1

Having the feature is worth the oddities of the syntax.

···

On Apr 5, 2017, at 4:01 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Proposal Link: https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md

Hello Swift community,

The review of SE-0161 “Smart KeyPaths: Better Key-Value Coding for Swift” ran from March 30...April 5, 2017. The proposal was very well-received *except* that reviewers felt that the keypath syntax was far too heavy for this new language construct, and preferred the lighter-weight syntax of the pre-review drafts. This proposal is returned for revision to address the syntax.

The heavyweight keypath syntax was requested by the core team after reviewing earlier drafts, which used a far lighter syntax:

  // (Rejected) syntax from pre-review drafts
  let firstFriendsNameKeyPath = Person.friends[0].name
  print(luke[keyPath: .friends[0].name])

The core team’s specific concern was that these key path expressions (e.g., Person.friends[0].name) don’t make it sufficiently clear that the actual property accesses are being delayed, and that the contextual cues (“Person." vs. “luke.”) are insufficient to disambiguate for the human reader. Hence, the request for a different (more explicit) syntax.

Reviewers rightly point out that it is natural for key-paths to use the same syntax as unapplied instance method references, e.g., Person.someInstanceMethod produces a value of some function type with the “Self” type curried, e.g., (Person) -> (param-types) -> result-type. The core team agrees with this sentiment. The core team also felt that Swift’s existing unapplied method references suffer from the same clarity problems as the initial key-path syntax, i.e., that it isn’t sufficiently clear that the actual application of “self” is being delayed.

The core team has a specific proposal: use the backslash (‘\’) to as a leading indicator for key paths. Specifically,

  // Proposed syntax for second revision
  let firstFriendsNameKeyPath = \Person.friends[0].name
  print(luke[keyPath: \.friends[0].name])

The backslash is a visual cue that the actual application of this chain of property references is delayed, eliminating ambiguities, yet is still quite lightweight and feels “first-class” in the language.

The core team felt that, in the future, the backslash should also be used for unapplied instance method references, to match the proposed syntax for key paths and improve clarity for this non obvious feature. This change could be staged in as a revision to the accepted-but-never-implemented SE-0042: Flattening the function type of unapplied method references <https://github.com/apple/swift-evolution/blob/master/proposals/0042-flatten-method-types.md&gt;, e.g.,

  // Proposed future syntax for unapplied instance method references
        class Person {
    func instanceMethod(_: String) -> Int { … }
  }

  let f1 = Person.instanceMethod // to-be-deprecated; produces a value of type (Person) -> (String) -> Int
  let f2 = \Person.instanceMethod // to-be-introduced via a revised SE-0042: produces a value of type (Person, String) -> Int

Such an approach gives us a way to stage in SE-0042 and get to eventual consistency between key paths and unapplied instance method references.

  - Doug
  Review Manager

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

Is the choice of backslash up for review? I think another operator,

We talked through basically everything on the keyboard, and there really aren’t other options that don’t stomp on existing behavior.

perhaps backtick (`), would work better.

Backtick (`) is already taken for escaping identifiers, e.g.,

  var `func` = { /* some code */ }

  - Doug

···

On Apr 5, 2017, at 4:55 PM, Colin Barrett <colin@springsandstruts.com> wrote:

Ah that's right. Too bad! As I said I see the logic behind all the changes,
so I'm not opposed. Just wanted to bikeshed the operator a bit.

Thanks Doug,
-Colin

···

On Wed, Apr 5, 2017 at 8:00 PM Douglas Gregor <dgregor@apple.com> wrote:

On Apr 5, 2017, at 4:55 PM, Colin Barrett <colin@springsandstruts.com> > wrote:

Is the choice of backslash up for review? I think another operator,

We talked through basically everything on the keyboard, and there really
aren’t other options that don’t stomp on existing behavior.

perhaps backtick (`), would work better.

Backtick (`) is already taken for escaping identifiers, e.g.,

var `func` = { /* some code */ }

- Doug

I too find the backslash odd, as it’s usually of course used to escape
something.

What about three periods?

let firstFriendsNameKeyPath = Person...friends[0].name
print(luke[keyPath: ...friends[0].name])

I also find wanting to use the same syntax for unapplied methods strange,
as they would product two totally different things: one a key path value,
the other a function.

Patrick

···

On Thu, 6 Apr 2017 at 10:00 am, Douglas Gregor via swift-evolution < swift-evolution@swift.org> wrote:

On Apr 5, 2017, at 4:55 PM, Colin Barrett <colin@springsandstruts.com> > wrote:

Is the choice of backslash up for review? I think another operator,

We talked through basically everything on the keyboard, and there really
aren’t other options that don’t stomp on existing behavior.

perhaps backtick (`), would work better.

Backtick (`) is already taken for escaping identifiers, e.g.,

var `func` = { /* some code */ }

- Doug

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

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

···

On Apr 5, 2017, at 5:16 PM, Patrick Smith via swift-evolution <swift-evolution@swift.org> wrote:

I too find the backslash odd, as it’s usually of course used to escape something.

What about three periods?

let firstFriendsNameKeyPath = Person...friends[0].name
print(luke[keyPath: ...friends[0].name])

I also find wanting to use the same syntax for unapplied methods strange, as they would product two totally different things: one a key path value, the other a function.

Patrick
On Thu, 6 Apr 2017 at 10:00 am, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 5, 2017, at 4:55 PM, Colin Barrett <colin@springsandstruts.com <mailto:colin@springsandstruts.com>> wrote:

Is the choice of backslash up for review? I think another operator,

We talked through basically everything on the keyboard, and there really aren’t other options that don’t stomp on existing behavior.

perhaps backtick (`), would work better.

Backtick (`) is already taken for escaping identifiers, e.g.,

  var `func` = { /* some code */ }

  - Doug

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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.

Matthew

···

On Apr 5, 2017, at 7:32 PM, David Smith via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 5, 2017, at 5:16 PM, Patrick Smith via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I too find the backslash odd, as it’s usually of course used to escape something.

What about three periods?

let firstFriendsNameKeyPath = Person...friends[0].name
print(luke[keyPath: ...friends[0].name])

I also find wanting to use the same syntax for unapplied methods strange, as they would product two totally different things: one a key path value, the other a function.

Patrick
On Thu, 6 Apr 2017 at 10:00 am, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 5, 2017, at 4:55 PM, Colin Barrett <colin@springsandstruts.com <mailto:colin@springsandstruts.com>> wrote:

Is the choice of backslash up for review? I think another operator,

We talked through basically everything on the keyboard, and there really aren’t other options that don’t stomp on existing behavior.

perhaps backtick (`), would work better.

Backtick (`) is already taken for escaping identifiers, e.g.,

  var `func` = { /* some code */ }

  - Doug

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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.

John.

···

On Apr 5, 2017, at 9:46 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 5, 2017, at 7:32 PM, David Smith via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Matthew

On Apr 5, 2017, at 5:16 PM, Patrick Smith via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I too find the backslash odd, as it’s usually of course used to escape something.

What about three periods?

let firstFriendsNameKeyPath = Person...friends[0].name
print(luke[keyPath: ...friends[0].name])

I also find wanting to use the same syntax for unapplied methods strange, as they would product two totally different things: one a key path value, the other a function.

Patrick
On Thu, 6 Apr 2017 at 10:00 am, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 5, 2017, at 4:55 PM, Colin Barrett <colin@springsandstruts.com <mailto:colin@springsandstruts.com>> wrote:

Is the choice of backslash up for review? I think another operator,

We talked through basically everything on the keyboard, and there really aren’t other options that don’t stomp on existing behavior.

perhaps backtick (`), would work better.

Backtick (`) is already taken for escaping identifiers, e.g.,

  var `func` = { /* some code */ }

  - Doug

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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?

As a secondary question, wouldn’t this be similar to the difference between generics and existentials? In theory the same optimizations could be applied but in practice they are not always right now. Is the plan to eventually put existentials on equal footing in terms of optimization?

···

On Apr 6, 2017, at 12:32 PM, John McCall <rjmccall@apple.com> wrote:

On Apr 5, 2017, at 9:46 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 5, 2017, at 7:32 PM, David Smith via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

John.

Matthew

On Apr 5, 2017, at 5:16 PM, Patrick Smith via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I too find the backslash odd, as it’s usually of course used to escape something.

What about three periods?

let firstFriendsNameKeyPath = Person...friends[0].name
print(luke[keyPath: ...friends[0].name])

I also find wanting to use the same syntax for unapplied methods strange, as they would product two totally different things: one a key path value, the other a function.

Patrick
On Thu, 6 Apr 2017 at 10:00 am, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 5, 2017, at 4:55 PM, Colin Barrett <colin@springsandstruts.com <mailto:colin@springsandstruts.com>> wrote:

Is the choice of backslash up for review? I think another operator,

We talked through basically everything on the keyboard, and there really aren’t other options that don’t stomp on existing behavior.

perhaps backtick (`), would work better.

Backtick (`) is already taken for escaping identifiers, e.g.,

  var `func` = { /* some code */ }

  - Doug

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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.

As a secondary question, wouldn’t this be similar to the difference between generics and existentials? In theory the same optimizations could be applied but in practice they are not always right now. Is the plan to eventually put existentials on equal footing in terms of optimization?

Eventually, yes, I think that's something we'd like make sure we can do.

John.

···

On Apr 6, 2017, at 1:41 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On Apr 6, 2017, at 12:32 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Apr 5, 2017, at 9:46 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 5, 2017, at 7:32 PM, David Smith via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

John.

Matthew

On Apr 5, 2017, at 5:16 PM, Patrick Smith via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I too find the backslash odd, as it’s usually of course used to escape something.

What about three periods?

let firstFriendsNameKeyPath = Person...friends[0].name
print(luke[keyPath: ...friends[0].name])

I also find wanting to use the same syntax for unapplied methods strange, as they would product two totally different things: one a key path value, the other a function.

Patrick
On Thu, 6 Apr 2017 at 10:00 am, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 5, 2017, at 4:55 PM, Colin Barrett <colin@springsandstruts.com <mailto:colin@springsandstruts.com>> wrote:

Is the choice of backslash up for review? I think another operator,

We talked through basically everything on the keyboard, and there really aren’t other options that don’t stomp on existing behavior.

perhaps backtick (`), would work better.

Backtick (`) is already taken for escaping identifiers, e.g.,

  var `func` = { /* some code */ }

  - Doug

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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.

-Joe

···

On Apr 6, 2017, at 11:06 AM, John McCall <rjmccall@apple.com> wrote:

On Apr 6, 2017, at 1:41 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On Apr 6, 2017, at 12:32 PM, John McCall <rjmccall@apple.com> wrote:

On Apr 5, 2017, at 9:46 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 5, 2017, at 7:32 PM, David Smith via swift-evolution <swift-evolution@swift.org> wrote:

As a secondary question, wouldn’t this be similar to the difference between generics and existentials? In theory the same optimizations could be applied but in practice they are not always right now. Is the plan to eventually put existentials on equal footing in terms of optimization?

Eventually, yes, I think that's something we'd like make sure we can do.

John.

John.

Matthew

On Apr 5, 2017, at 5:16 PM, Patrick Smith via swift-evolution <swift-evolution@swift.org> wrote:

I too find the backslash odd, as it’s usually of course used to escape something.

What about three periods?

let firstFriendsNameKeyPath = Person...friends[0].name
print(luke[keyPath: ...friends[0].name])

I also find wanting to use the same syntax for unapplied methods strange, as they would product two totally different things: one a key path value, the other a function.

Patrick
On Thu, 6 Apr 2017 at 10:00 am, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 5, 2017, at 4:55 PM, Colin Barrett <colin@springsandstruts.com> wrote:

Is the choice of backslash up for review? I think another operator,

We talked through basically everything on the keyboard, and there really aren’t other options that don’t stomp on existing behavior.

perhaps backtick (`), would work better.

Backtick (`) is already taken for escaping identifiers, e.g.,

  var `func` = { /* some code */ }

  - Doug

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

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

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

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.

Key paths in this proposal are classes which require storage of the pointer as well as reference counting unless there is special of key path values. Is something like that planned? I could imagine some kind of tagged pointer might be possible but I can’t imagine how you would eliminate the need to store a word. It’s not that much overhead but it would still be nice to be able to avoid it when all we’re doing is passing a stateless function reference.

···

On Apr 6, 2017, at 1:06 PM, John McCall <rjmccall@apple.com> wrote:

On Apr 6, 2017, at 1:41 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

On Apr 6, 2017, at 12:32 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Apr 5, 2017, at 9:46 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 5, 2017, at 7:32 PM, David Smith via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

As a secondary question, wouldn’t this be similar to the difference between generics and existentials? In theory the same optimizations could be applied but in practice they are not always right now. Is the plan to eventually put existentials on equal footing in terms of optimization?

Eventually, yes, I think that's something we'd like make sure we can do.

John.

John.

Matthew

On Apr 5, 2017, at 5:16 PM, Patrick Smith via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I too find the backslash odd, as it’s usually of course used to escape something.

What about three periods?

let firstFriendsNameKeyPath = Person...friends[0].name
print(luke[keyPath: ...friends[0].name])

I also find wanting to use the same syntax for unapplied methods strange, as they would product two totally different things: one a key path value, the other a function.

Patrick
On Thu, 6 Apr 2017 at 10:00 am, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 5, 2017, at 4:55 PM, Colin Barrett <colin@springsandstruts.com <mailto:colin@springsandstruts.com>> wrote:

Is the choice of backslash up for review? I think another operator,

We talked through basically everything on the keyboard, and there really aren’t other options that don’t stomp on existing behavior.

perhaps backtick (`), would work better.

Backtick (`) is already taken for escaping identifiers, e.g.,

  var `func` = { /* some code */ }

  - Doug

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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.

Key paths in this proposal are classes which require storage of the pointer as well as reference counting unless there is special of key path values. Is something like that planned? I could imagine some kind of tagged pointer might be possible but I can’t imagine how you would eliminate the need to store a word. It’s not that much overhead but it would still be nice to be able to avoid it when all we’re doing is passing a stateless function reference.

Are you under the impression that run-time generics don't require passing extra pointers around?

John.

···

On Apr 6, 2017, at 2:12 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On Apr 6, 2017, at 1:06 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Apr 6, 2017, at 1:41 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

On Apr 6, 2017, at 12:32 PM, John McCall <rjmccall@apple.com <mailto:rjmccall@apple.com>> wrote:

On Apr 5, 2017, at 9:46 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 5, 2017, at 7:32 PM, David Smith via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

As a secondary question, wouldn’t this be similar to the difference between generics and existentials? In theory the same optimizations could be applied but in practice they are not always right now. Is the plan to eventually put existentials on equal footing in terms of optimization?

Eventually, yes, I think that's something we'd like make sure we can do.

John.

John.

Matthew

On Apr 5, 2017, at 5:16 PM, Patrick Smith via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I too find the backslash odd, as it’s usually of course used to escape something.

What about three periods?

let firstFriendsNameKeyPath = Person...friends[0].name
print(luke[keyPath: ...friends[0].name])

I also find wanting to use the same syntax for unapplied methods strange, as they would product two totally different things: one a key path value, the other a function.

Patrick
On Thu, 6 Apr 2017 at 10:00 am, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Apr 5, 2017, at 4:55 PM, Colin Barrett <colin@springsandstruts.com <mailto:colin@springsandstruts.com>> wrote:

Is the choice of backslash up for review? I think another operator,

We talked through basically everything on the keyboard, and there really aren’t other options that don’t stomp on existing behavior.

perhaps backtick (`), would work better.

Backtick (`) is already taken for escaping identifiers, e.g.,

  var `func` = { /* some code */ }

  - Doug

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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?

Can you elaborate on the high-level optimizations you have in mind? 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?

···

On Apr 6, 2017, at 1:11 PM, Joe Groff <jgroff@apple.com> wrote:

On Apr 6, 2017, at 11:06 AM, John McCall <rjmccall@apple.com> wrote:

On Apr 6, 2017, at 1:41 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On Apr 6, 2017, at 12:32 PM, John McCall <rjmccall@apple.com> wrote:

On Apr 5, 2017, at 9:46 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 5, 2017, at 7:32 PM, David Smith via swift-evolution <swift-evolution@swift.org> wrote:

-Joe

As a secondary question, wouldn’t this be similar to the difference between generics and existentials? In theory the same optimizations could be applied but in practice they are not always right now. Is the plan to eventually put existentials on equal footing in terms of optimization?

Eventually, yes, I think that's something we'd like make sure we can do.

John.

John.

Matthew

On Apr 5, 2017, at 5:16 PM, Patrick Smith via swift-evolution <swift-evolution@swift.org> wrote:

I too find the backslash odd, as it’s usually of course used to escape something.

What about three periods?

let firstFriendsNameKeyPath = Person...friends[0].name
print(luke[keyPath: ...friends[0].name])

I also find wanting to use the same syntax for unapplied methods strange, as they would product two totally different things: one a key path value, the other a function.

Patrick
On Thu, 6 Apr 2017 at 10:00 am, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 5, 2017, at 4:55 PM, Colin Barrett <colin@springsandstruts.com> wrote:

Is the choice of backslash up for review? I think another operator,

We talked through basically everything on the keyboard, and there really aren’t other options that don’t stomp on existing behavior.

perhaps backtick (`), would work better.

Backtick (`) is already taken for escaping identifiers, e.g.,

  var `func` = { /* some code */ }

  - Doug

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

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

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