Smart KeyPaths


(Vladimir) #1

+1. This is my favorite solution so far.

With ‘Person.keypath.name' it is obvious that we are creating a key
path. There is no ambiguity for the reader. With autocomplete it will
be very little extra typing anyway…

But that adds a lot of verbosity. They disregarded #keyPath because it
was too verbose.

The syntax in the original proposal is terse and elegant, and will
probably be fine when a developer who is experienced with Swift and a
particular codebase is first writing the code. Using “key path” or
“keypaths” of perhaps a shorter term or even a single leading character
(`#` ?) will make this feature more discoverable, tool-friendly and its
usages more maintainable.

An extra term or character does add verbosity. How much is subjective,
but I would not call it “a lot”. It does not add any nesting or code
complexity. KVO code is usually a small fraction of most Objective-C
projects (in my experience, at least) and it is probably safe to assume
that the usage of this feature in Swift will be similar.

Verbosity vs clarity is often a tradeoff and I think that on balance, for
a feature like this a little extra verbosity is worth it. Swift does not
have the most terse syntax possible. `++` was removed, for example.

Just because an assignment is already implicitly typed in Swift does not
mean that the ambiguity has to keep increasing without end for
implementation of all new features, especially for ones that are not used
very frequently.

+1 to all of this.

Particularly the point that KVO code typically is a small portion of the
overall code; this not only makes the added verbosity not that
egregious—certainly less so than “try” or “override”—but it also
underscores the fact that as a relatively uncommon feature, it’s not what a
reader of the code is going to be expecting to see. This latter point is
why I feel that without some kind of additional syntax—even if it’s just
one character—key paths will frequently get mistaken for property accesses
if they are implemented this way.

+1 from me. The problem is not that we shouldn't have instance props with the same name as class/static props. The problem is when you are *reading* some code(not always in IDE) it is hard to say what MyType.someprop[atIndex].name means. Is it static/class property or is it KeyPath? You just don't know - you have to check this in MyType declaration for any static property you don't know for sure it is static .

The same is for instance:

struct S {
  var index = 0
  func foo() {}
  subscript (at: Int) -> Int {return at*100}
}
//....
let s = S()
let value = s[index]
// is it key path or subscript with `index` as parameter?

The difference with unbound methods(I hope I correctly understand that unbound method is `T.method` as mentioned by the proposal) is that unbound method IMO don't have *such* level of confusing. It can't have subscripts, it can't contains more than one part(the method name itself).

Also, using the above code,
let method = S.foo

this line *has* a marker, that here we have an unbound method : there is *no* `()` after the foo. Do we have any such 'marker' in proposed key paths? No.

So I do believe this special feature(I mean it will be used rarely and reader most likely will not expect it in the code) requires a special syntax highlighting.

FWIW, currently I do like 3 proposed syntax to highlight what is happening here and also is not verbose like #keyPath():

1. Type:path and instance:path

2. Type@path and instance@path - as it reads nice "type at path" and "instance at path"

3. And also I think as soon as we have `#` as marker for 'compiler magic', IMO it will be logically use it for the feature:
Type#path and instance#path.

···

On 20.03.2017 17:56, Charles Srstka via swift-evolution wrote:

On Mar 20, 2017, at 9:23 AM, Christopher Kornher via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Mar 20, 2017, at 5:12 AM, David Hart via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 20 Mar 2017, at 10:39, Jonathan Hull via swift-evolution >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Charles

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


(Matthew Johnson) #2

+1. This is my favorite solution so far.

With ‘Person.keypath.name' it is obvious that we are creating a key
path. There is no ambiguity for the reader. With autocomplete it will
be very little extra typing anyway…

But that adds a lot of verbosity. They disregarded #keyPath because it
was too verbose.

The syntax in the original proposal is terse and elegant, and will
probably be fine when a developer who is experienced with Swift and a
particular codebase is first writing the code. Using “key path” or
“keypaths” of perhaps a shorter term or even a single leading character
(`#` ?) will make this feature more discoverable, tool-friendly and its
usages more maintainable.

An extra term or character does add verbosity. How much is subjective,
but I would not call it “a lot”. It does not add any nesting or code
complexity. KVO code is usually a small fraction of most Objective-C
projects (in my experience, at least) and it is probably safe to assume
that the usage of this feature in Swift will be similar.

Verbosity vs clarity is often a tradeoff and I think that on balance, for
a feature like this a little extra verbosity is worth it. Swift does not
have the most terse syntax possible. `++` was removed, for example.

Just because an assignment is already implicitly typed in Swift does not
mean that the ambiguity has to keep increasing without end for
implementation of all new features, especially for ones that are not used
very frequently.

+1 to all of this.

Particularly the point that KVO code typically is a small portion of the
overall code; this not only makes the added verbosity not that
egregious—certainly less so than “try” or “override”—but it also
underscores the fact that as a relatively uncommon feature, it’s not what a
reader of the code is going to be expecting to see. This latter point is
why I feel that without some kind of additional syntax—even if it’s just
one character—key paths will frequently get mistaken for property accesses
if they are implemented this way.

+1 from me. The problem is not that we shouldn't have instance props with the same name as class/static props. The problem is when you are *reading* some code(not always in IDE) it is hard to say what MyType.someprop[atIndex].name means. Is it static/class property or is it KeyPath? You just don't know - you have to check this in MyType declaration for any static property you don't know for sure it is static .

The same is for instance:

struct S {
  var index = 0
  func foo() {}
  subscript (at: Int) -> Int {return at*100}
}
//....
let s = S()
let value = s[index]
// is it key path or subscript with `index` as parameter?

The difference with unbound methods(I hope I correctly understand that unbound method is `T.method` as mentioned by the proposal) is that unbound method IMO don't have *such* level of confusing. It can't have subscripts, it can't contains more than one part(the method name itself).

Yes, this is a difference that matters in some respects.

Also, using the above code,
let method = S.foo

this line *has* a marker, that here we have an unbound method : there is *no* `()` after the foo. Do we have any such 'marker' in proposed key paths? No.

So I do believe this special feature(I mean it will be used rarely and reader most likely will not expect it in the code) requires a special syntax highlighting.

FWIW, currently I do like 3 proposed syntax to highlight what is happening here and also is not verbose like #keyPath():

1. Type:path and instance:path

2. Type@path and instance@path - as it reads nice "type at path" and "instance at path"

3. And also I think as soon as we have `#` as marker for 'compiler magic', IMO it will be logically use it for the feature:
Type#path and instance#path.

Hmm, I could live with this approach (#) as long as the dot shorthand still worked in type contexts expecting a key path with a concrete Root.

···

On Mar 20, 2017, at 12:37 PM, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:
On 20.03.2017 17:56, Charles Srstka via swift-evolution wrote:

On Mar 20, 2017, at 9:23 AM, Christopher Kornher via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Mar 20, 2017, at 5:12 AM, David Hart via swift-evolution >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 20 Mar 2017, at 10:39, Jonathan Hull via swift-evolution >>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Charles

_______________________________________________
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


(Ricardo Parada) #3

If a character had to be used to denote key paths then I would prefer this one:

1. Type:path.to.value and instance:path.to.value

I feel like the # screams at me. :slight_smile:

···

On Mar 20, 2017, at 1:52 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Mar 20, 2017, at 12:37 PM, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

On 20.03.2017 17:56, Charles Srstka via swift-evolution wrote:

On Mar 20, 2017, at 9:23 AM, Christopher Kornher via swift-evolution >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Mar 20, 2017, at 5:12 AM, David Hart via swift-evolution >>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 20 Mar 2017, at 10:39, Jonathan Hull via swift-evolution >>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

+1. This is my favorite solution so far.

With ‘Person.keypath.name' it is obvious that we are creating a key
path. There is no ambiguity for the reader. With autocomplete it will
be very little extra typing anyway…

But that adds a lot of verbosity. They disregarded #keyPath because it
was too verbose.

The syntax in the original proposal is terse and elegant, and will
probably be fine when a developer who is experienced with Swift and a
particular codebase is first writing the code. Using “key path” or
“keypaths” of perhaps a shorter term or even a single leading character
(`#` ?) will make this feature more discoverable, tool-friendly and its
usages more maintainable.

An extra term or character does add verbosity. How much is subjective,
but I would not call it “a lot”. It does not add any nesting or code
complexity. KVO code is usually a small fraction of most Objective-C
projects (in my experience, at least) and it is probably safe to assume
that the usage of this feature in Swift will be similar.

Verbosity vs clarity is often a tradeoff and I think that on balance, for
a feature like this a little extra verbosity is worth it. Swift does not
have the most terse syntax possible. `++` was removed, for example.

Just because an assignment is already implicitly typed in Swift does not
mean that the ambiguity has to keep increasing without end for
implementation of all new features, especially for ones that are not used
very frequently.

+1 to all of this.

Particularly the point that KVO code typically is a small portion of the
overall code; this not only makes the added verbosity not that
egregious—certainly less so than “try” or “override”—but it also
underscores the fact that as a relatively uncommon feature, it’s not what a
reader of the code is going to be expecting to see. This latter point is
why I feel that without some kind of additional syntax—even if it’s just
one character—key paths will frequently get mistaken for property accesses
if they are implemented this way.

+1 from me. The problem is not that we shouldn't have instance props with the same name as class/static props. The problem is when you are *reading* some code(not always in IDE) it is hard to say what MyType.someprop[atIndex].name means. Is it static/class property or is it KeyPath? You just don't know - you have to check this in MyType declaration for any static property you don't know for sure it is static .

The same is for instance:

struct S {
   var index = 0
   func foo() {}
   subscript (at: Int) -> Int {return at*100}
}
//....
let s = S()
let value = s[index]
// is it key path or subscript with `index` as parameter?

The difference with unbound methods(I hope I correctly understand that unbound method is `T.method` as mentioned by the proposal) is that unbound method IMO don't have *such* level of confusing. It can't have subscripts, it can't contains more than one part(the method name itself).

Yes, this is a difference that matters in some respects.

Also, using the above code,
let method = S.foo

this line *has* a marker, that here we have an unbound method : there is *no* `()` after the foo. Do we have any such 'marker' in proposed key paths? No.

So I do believe this special feature(I mean it will be used rarely and reader most likely will not expect it in the code) requires a special syntax highlighting.

FWIW, currently I do like 3 proposed syntax to highlight what is happening here and also is not verbose like #keyPath():

1. Type:path and instance:path

2. Type@path and instance@path - as it reads nice "type at path" and "instance at path"

3. And also I think as soon as we have `#` as marker for 'compiler magic', IMO it will be logically use it for the feature:
Type#path and instance#path.

Hmm, I could live with this approach (#) as long as the dot shorthand still worked in type contexts expecting a key path with a concrete Root.

Charles

_______________________________________________
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


(Brent Royal-Gordon) #4

If I write `foo[instance:path.to.value]`, how is Swift to know whether that's a key path or an argument label?

···

On Mar 20, 2017, at 9:12 PM, Ricardo Parada via swift-evolution <swift-evolution@swift.org> wrote:

If a character had to be used to denote key paths then I would prefer this one:

1. Type:path.to.value and instance:path.to.value

I feel like the # screams at me. :slight_smile:

--
Brent Royal-Gordon
Architechies


(Ricardo Parada) #5

You are right. I did not think of that.

···

Sent from my iPhone

On Mar 21, 2017, at 5:34 AM, Brent Royal-Gordon <brent@architechies.com> wrote:

On Mar 20, 2017, at 9:12 PM, Ricardo Parada via swift-evolution <swift-evolution@swift.org> wrote:

If a character had to be used to denote key paths then I would prefer this one:

1. Type:path.to.value and instance:path.to.value

I feel like the # screams at me. :slight_smile:

If I write `foo[instance:path.to.value]`, how is Swift to know whether that's a key path or an argument label?

--
Brent Royal-Gordon
Architechies