Proposal: Expose getter/setters in the same way as regular methods


(Michael Henson) #1

Swift-like full KVO/KVC as in Objective-C is a stated long-term goal for
Swift's evolution. The 90% solution might be more straightforward:

class Example {
  var member: String

  func print() {
    print(self.member)
  }
}

var example = Example(member: "Hi!")

var example_print_method = example.print
example_print_method()
result:
Hi!

If there were a mechanism for referring to the getter and setter methods on
the var member property as the same kind of self-capturing closures, it
could make simple cases of data binding easier to implement:

var serializeFields = [
  "member": example.member#get,
]

var deserializeFields = [
  "member": example.member#set,
]

var broadcastValueTo = [
  "memberValues": [
     example.member#set,
     example2.member#set,
     example3.member#set,
  ]
]

viewController.textField.onValueChanged(example.member#set)

Etc.

The "#" notation is just a placeholder for "whatever mechanism is decided
upon", though it does seem to be available and using it postfix makes a
first-glance sense to me in terms of the semantics of expressions.

Mike


(Marc Knaup) #2

Wait, where is stated that KVO is a long-term goal for Swift? I might have
missed that.

I find that one of Objective-C's most annoying features. It makes it really
difficult to reason about code when things can happen unexpectedly left and
right. It's the same issue with aspect-oriented programming.

I prefer explicit integration points like closures, delegates and alike.
Most times I used KVO in the past was to work around bugs or annoyances on
iOS, like for example forcing a button stay enabled even when iOS disables
it.

Also it's unlikely that all mutable properties will support observation
automatically. That would require the optimizer to keep using dynamic
dispatch for all of them which will hurt performance.

But I'm getting off-topic since your discussion is not about KVO nor about
KVC.

Being able to refer to getters and setters is a good idea and aligns with
being able to refer to initializers and methods.
I would also add subscripts to the list if possible.

···

On Mon, Dec 14, 2015 at 1:34 AM, Michael Henson via swift-evolution < swift-evolution@swift.org> wrote:

Swift-like full KVO/KVC as in Objective-C is a stated long-term goal for
Swift's evolution. The 90% solution might be more straightforward:

class Example {
  var member: String

  func print() {
    print(self.member)
  }
}

var example = Example(member: "Hi!")

var example_print_method = example.print
example_print_method()
result:
Hi!

If there were a mechanism for referring to the getter and setter methods
on the var member property as the same kind of self-capturing closures, it
could make simple cases of data binding easier to implement:

var serializeFields = [
  "member": example.member#get,
]

var deserializeFields = [
  "member": example.member#set,
]

var broadcastValueTo = [
  "memberValues": [
     example.member#set,
     example2.member#set,
     example3.member#set,
  ]
]

viewController.textField.onValueChanged(example.member#set)

Etc.

The "#" notation is just a placeholder for "whatever mechanism is decided
upon", though it does seem to be available and using it postfix makes a
first-glance sense to me in terms of the semantics of expressions.

Mike

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


(Joe Groff) #3

This is something I'm looking into. Providing the getter is valuable, but setters are not usually very useful by themselves. With value types, you need the full property interface to be able to drill further down into the value and update part of the value, since you potentially need recursive writeback. Furthermore, the get/set protocol is inefficient for copy-on-write types, since it forces a temporary copy when doing partial updates; Swift's property model provides a third implicit "materializeForSet" accessor that preserves in-place update when going through abstractions such as overrideable class properties, properties in generics, or properties across resilience boundaries. There are even more shenanigans we're planning to make mutations through array slices and the like efficient too. To that end, I think the two things you want of a property are:

- its getter, since read-only access is definitely useful for things like `map`, and
- what i'll call its "lens", notionally a function T -> inout U, which captures the full property interface. You can apply the function in mutable contexts without sacrificing efficiency or composability, and derive the getter/setter functions fairly straightforwardly.

-Joe

···

On Dec 13, 2015, at 4:34 PM, Michael Henson via swift-evolution <swift-evolution@swift.org> wrote:

Swift-like full KVO/KVC as in Objective-C is a stated long-term goal for Swift's evolution. The 90% solution might be more straightforward:

class Example {
  var member: String

  func print() {
    print(self.member)
  }
}

var example = Example(member: "Hi!")

var example_print_method = example.print
example_print_method()
result:
Hi!

If there were a mechanism for referring to the getter and setter methods on the var member property as the same kind of self-capturing closures, it could make simple cases of data binding easier to implement:

var serializeFields = [
  "member": example.member#get,
]

var deserializeFields = [
  "member": example.member#set,
]

var broadcastValueTo = [
  "memberValues": [
     example.member#set,
     example2.member#set,
     example3.member#set,
  ]
]

viewController.textField.onValueChanged(example.member#set)

Etc.

The "#" notation is just a placeholder for "whatever mechanism is decided upon", though it does seem to be available and using it postfix makes a first-glance sense to me in terms of the semantics of expressions.

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


(Matthew Johnson) #4

I find that (KVO) one of Objective-C's most annoying features. It makes it really difficult to reason about code when things can happen unexpectedly left and right. It's the same issue with aspect-oriented programming.

I prefer explicit integration points like closures, delegates and alike.

+1. I especially dislike system APIs that offer no alternatives to KVO when communicating with clients. I hope we can at least avoid that mistake in Swift-native API designs.

Being able to refer to getters and setters is a good idea and aligns with being able to refer to initializers and methods.
I would also add subscripts to the list if possible.

+1 to this as well.


(ilya) #5

Being able to refer to getters and setters is a good idea and aligns with

being able to refer to initializers and methods.

I would also add subscripts to the list if possible.

Great idea! Let's discuss syntax

How about
- example.get.member
- example.set.member
- example.init(argument:Int, another:String)
- example.subscript(index:Int)

···

On Mon, Dec 14, 2015 at 3:49 AM, Marc Knaup via swift-evolution < swift-evolution@swift.org> wrote:

Wait, where is stated that KVO is a long-term goal for Swift? I might have
missed that.

I find that one of Objective-C's most annoying features. It makes it
really difficult to reason about code when things can happen unexpectedly
left and right. It's the same issue with aspect-oriented programming.

I prefer explicit integration points like closures, delegates and alike.
Most times I used KVO in the past was to work around bugs or annoyances on
iOS, like for example forcing a button stay enabled even when iOS disables
it.

Also it's unlikely that all mutable properties will support observation
automatically. That would require the optimizer to keep using dynamic
dispatch for all of them which will hurt performance.

But I'm getting off-topic since your discussion is not about KVO nor about
KVC.

Being able to refer to getters and setters is a good idea and aligns with
being able to refer to initializers and methods.
I would also add subscripts to the list if possible.

On Mon, Dec 14, 2015 at 1:34 AM, Michael Henson via swift-evolution < > swift-evolution@swift.org> wrote:

Swift-like full KVO/KVC as in Objective-C is a stated long-term goal for
Swift's evolution. The 90% solution might be more straightforward:

class Example {
  var member: String

  func print() {
    print(self.member)
  }
}

var example = Example(member: "Hi!")

var example_print_method = example.print
example_print_method()
result:
Hi!

If there were a mechanism for referring to the getter and setter methods
on the var member property as the same kind of self-capturing closures, it
could make simple cases of data binding easier to implement:

var serializeFields = [
  "member": example.member#get,
]

var deserializeFields = [
  "member": example.member#set,
]

var broadcastValueTo = [
  "memberValues": [
     example.member#set,
     example2.member#set,
     example3.member#set,
  ]
]

viewController.textField.onValueChanged(example.member#set)

Etc.

The "#" notation is just a placeholder for "whatever mechanism is decided
upon", though it does seem to be available and using it postfix makes a
first-glance sense to me in terms of the semantics of expressions.

Mike

_______________________________________________
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


(Pierre Monod-Broca) #6

It could be used in that kind of way too (illustrating with the ‘#' syntax suggestion):

class Foo {
    var name: String
}

let getter = Foo.name#get // (Foo) -> () -> (String)
let setter = Foo.name#set // (Foo) -> (String) -> ()

let foo = Foo(name: "f")
getter(foo)() // "f"
setter(foo)("g") // now foo.name == "g"

It might be the similar with struct:

struct Bar {
    var name: String
}

let getter = Bar.name#get // (Bar) -> () -> (String)
let setter = Bar.name#set // (inout Bar) -> (String) -> ()

var bar = Bar(name: "f") // note bar is a var
getter(bar)() // "f"
setter(&bar)("g") // now foo.name == "g"

Pierre

···

Le 17 déc. 2015 à 03:59, Joe Groff via swift-evolution <swift-evolution@swift.org> a écrit :

This is something I'm looking into. Providing the getter is valuable, but setters are not usually very useful by themselves. With value types, you need the full property interface to be able to drill further down into the value and update part of the value, since you potentially need recursive writeback. Furthermore, the get/set protocol is inefficient for copy-on-write types, since it forces a temporary copy when doing partial updates; Swift's property model provides a third implicit "materializeForSet" accessor that preserves in-place update when going through abstractions such as overrideable class properties, properties in generics, or properties across resilience boundaries. There are even more shenanigans we're planning to make mutations through array slices and the like efficient too. To that end, I think the two things you want of a property are:

- its getter, since read-only access is definitely useful for things like `map`, and
- what i'll call its "lens", notionally a function T -> inout U, which captures the full property interface. You can apply the function in mutable contexts without sacrificing efficiency or composability, and derive the getter/setter functions fairly straightforwardly.

-Joe

On Dec 13, 2015, at 4:34 PM, Michael Henson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Swift-like full KVO/KVC as in Objective-C is a stated long-term goal for Swift's evolution. The 90% solution might be more straightforward:

class Example {
  var member: String

  func print() {
    print(self.member)
  }
}

var example = Example(member: "Hi!")

var example_print_method = example.print
example_print_method()
result:
Hi!

If there were a mechanism for referring to the getter and setter methods on the var member property as the same kind of self-capturing closures, it could make simple cases of data binding easier to implement:

var serializeFields = [
  "member": example.member#get,
]

var deserializeFields = [
  "member": example.member#set,
]

var broadcastValueTo = [
  "memberValues": [
     example.member#set,
     example2.member#set,
     example3.member#set,
  ]
]

viewController.textField.onValueChanged(example.member#set)

Etc.

The "#" notation is just a placeholder for "whatever mechanism is decided upon", though it does seem to be available and using it postfix makes a first-glance sense to me in terms of the semantics of expressions.

Mike
_______________________________________________
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


(Michael Henson) #7

Another option for handling this occurred to me - an "export list" in the
lexical block that usually declares getters, setters, and will/didSet:

class Thing {
  var property: String {
    [get, set]
  }
}

It's somewhat like a "capture list" syntax but in the context of the
accessor declarations. The function is that it explicitly declares which of
the methods should be exposed to the outside world - much like the
auto-generated methods for properties in Objective-C. There would be a
defined naming scheme for generated methods, perhaps a way to override the
default name for special cases, etc. The generated/exported funcs are then
just like every other func declared on the type.

Is there a strong inclination on the internal team to add features like
this only if they can apply as broadly as possible, all at once?

Mike

···

This is something I'm looking into. Providing the getter is valuable, but
setters are not usually very useful by themselves. With value types, you
need the full property interface to be able to drill further down into the
value and update part of the value, since you potentially need recursive
writeback. Furthermore, the get/set protocol is inefficient for
copy-on-write types, since it forces a temporary copy when doing partial
updates; Swift's property model provides a third implicit
"materializeForSet" accessor that preserves in-place update when going
through abstractions such as overrideable class properties, properties in
generics, or properties across resilience boundaries. There are even more
shenanigans we're planning to make mutations through array slices and the
like efficient too. To that end, I think the two things you want of a
property are:
- its getter, since read-only access is definitely useful for things like
`map`, and
- what i'll call its "lens", notionally a function T -> inout U, which
captures the full property interface. You can apply the function in mutable
contexts without sacrificing efficiency or composability, and derive the
getter/setter functions fairly straightforwardly.

On Wed, Dec 16, 2015 at 6:59 PM, Joe Groff <jgroff@apple.com> wrote:

This is something I'm looking into. Providing the getter is valuable, but
setters are not usually very useful by themselves. With value types, you
need the full property interface to be able to drill further down into the
value and update part of the value, since you potentially need recursive
writeback. Furthermore, the get/set protocol is inefficient for
copy-on-write types, since it forces a temporary copy when doing partial
updates; Swift's property model provides a third implicit
"materializeForSet" accessor that preserves in-place update when going
through abstractions such as overrideable class properties, properties in
generics, or properties across resilience boundaries. There are even more
shenanigans we're planning to make mutations through array slices and the
like efficient too. To that end, I think the two things you want of a
property are:

- its getter, since read-only access is definitely useful for things like
`map`, and
- what i'll call its "lens", notionally a function T -> inout U, which
captures the full property interface. You can apply the function in mutable
contexts without sacrificing efficiency or composability, and derive the
getter/setter functions fairly straightforwardly.

-Joe

On Dec 13, 2015, at 4:34 PM, Michael Henson via swift-evolution < > swift-evolution@swift.org> wrote:

Swift-like full KVO/KVC as in Objective-C is a stated long-term goal for
Swift's evolution. The 90% solution might be more straightforward:

class Example {
  var member: String

  func print() {
    print(self.member)
  }
}

var example = Example(member: "Hi!")

var example_print_method = example.print
example_print_method()
result:
Hi!

If there were a mechanism for referring to the getter and setter methods
on the var member property as the same kind of self-capturing closures, it
could make simple cases of data binding easier to implement:

var serializeFields = [
  "member": example.member#get,
]

var deserializeFields = [
  "member": example.member#set,
]

var broadcastValueTo = [
  "memberValues": [
     example.member#set,
     example2.member#set,
     example3.member#set,
  ]
]

viewController.textField.onValueChanged(example.member#set)

Etc.

The "#" notation is just a placeholder for "whatever mechanism is decided
upon", though it does seem to be available and using it postfix makes a
first-glance sense to me in terms of the semantics of expressions.

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


(Charles Srstka) #8

Not really. All that’s required for Objective-C KVO to work for a stored property is for the willChangeValueForKey() and didChangeValueForKey() methods to be called before and after the value is set. If you put those calls in willSet and didSet for a Swift stored property, you can get KVO compliance with no dynamic dispatch at all. The reason Objective-C typically requires dynamic dispatch for this is because KVO is purely a framework-level feature, and is not built into the library, so the framework code has to rewrite your class to add the needed methods. If you built a KVO-like system right into the language, the notification methods could be added right at compile time, and it’d work fine. Of course, if I were redesigning KVO, I’d probably eliminate willChangeValueForKey() and just include the old value as a parameter to didChangeValueForKey(), since if there’s only one method to call, you can set the property on a secondary thread, and then just call the observation method asynchronously on the main thread, which will avoid tying up the worker thread waiting for UI updates that result from the KVO update.

Of course, if you’re worried about the performance costs associated with that extra method call, you might want to include a keyword, such as “observable”, and only generate the method call(s) if that keyword is on the property. This would probably be a good thing *anyway*, since one of the weaknesses of the current KVO implementation is that there’s no way to know whether a property is KVO observable or not without reading the documentation for that method, since computed properties need to state their dependencies in order to property support KVO, and whether this has been done is not reflected in the interface at all.

Charles

···

On Dec 13, 2015, at 6:49 PM, Marc Knaup via swift-evolution <swift-evolution@swift.org> wrote:

Also it's unlikely that all mutable properties will support observation automatically. That would require the optimizer to keep using dynamic dispatch for all of them which will hurt performance.


(Pierre Monod-Broca) #9

+1

I like the #get, #set suffixes.

I’m afraid the following would be a bit ambiguous

- example.init(argument:Int, another:String)
- example.subscript(index:Int)

Maybe with ‘#’ too
- example.init#argument:Int#another:String
- example.init#argument#another
- example.init#(argument:Int, another:String)
- example.subscript#index:Int
- example.subscript#Int

Pierre

···

Le 14 déc. 2015 à 08:57, ilya via swift-evolution <swift-evolution@swift.org> a écrit :

> Being able to refer to getters and setters is a good idea and aligns with being able to refer to initializers and methods.
> I would also add subscripts to the list if possible.

Great idea! Let's discuss syntax

How about
- example.get.member
- example.set.member
- example.init(argument:Int, another:String)
- example.subscript(index:Int)

On Mon, Dec 14, 2015 at 3:49 AM, Marc Knaup via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Wait, where is stated that KVO is a long-term goal for Swift? I might have missed that.

I find that one of Objective-C's most annoying features. It makes it really difficult to reason about code when things can happen unexpectedly left and right. It's the same issue with aspect-oriented programming.

I prefer explicit integration points like closures, delegates and alike.
Most times I used KVO in the past was to work around bugs or annoyances on iOS, like for example forcing a button stay enabled even when iOS disables it.

Also it's unlikely that all mutable properties will support observation automatically. That would require the optimizer to keep using dynamic dispatch for all of them which will hurt performance.

But I'm getting off-topic since your discussion is not about KVO nor about KVC.

Being able to refer to getters and setters is a good idea and aligns with being able to refer to initializers and methods.
I would also add subscripts to the list if possible.

On Mon, Dec 14, 2015 at 1:34 AM, Michael Henson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Swift-like full KVO/KVC as in Objective-C is a stated long-term goal for Swift's evolution. The 90% solution might be more straightforward:

class Example {
  var member: String

  func print() {
    print(self.member)
  }
}

var example = Example(member: "Hi!")

var example_print_method = example.print
example_print_method()
result:
Hi!

If there were a mechanism for referring to the getter and setter methods on the var member property as the same kind of self-capturing closures, it could make simple cases of data binding easier to implement:

var serializeFields = [
  "member": example.member#get,
]

var deserializeFields = [
  "member": example.member#set,
]

var broadcastValueTo = [
  "memberValues": [
     example.member#set,
     example2.member#set,
     example3.member#set,
  ]
]

viewController.textField.onValueChanged(example.member#set)

Etc.

The "#" notation is just a placeholder for "whatever mechanism is decided upon", though it does seem to be available and using it postfix makes a first-glance sense to me in terms of the semantics of expressions.

Mike

_______________________________________________
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


(Adrian Kashivskyy) #10

+1, I like this idea! I'm not sure if I like `#`, though – maybe the type should be inferred, much like when using `init`s?

struct Foo {
  init(_: Int) {}
  init(_: String) {}
}

// this infers the int setter
let intInit: (Int) -> Foo = Foo.init

// this infers the string setter
let stringInit: (String) -> Foo = Foo.init

Note that you cannot explicitly refer to a specific `init`. My proposal is to use the same technique when referring to getters and setters:

struct Foo {
  let bar: Int
}

// this just reads the value
let value = Foo.bar

// this infers a getter
let getter: () -> Int = Foo().bar

// this infers a setter
let setter: (Int) -> Void = Foo().bar

Pozdrawiam – Regards,
Adrian Kashivskyy

···

Wiadomość napisana przez Pierre Monod-Broca via swift-evolution <swift-evolution@swift.org> w dniu 14.12.2015, o godz. 09:25:

+1

I like the #get, #set suffixes.

I’m afraid the following would be a bit ambiguous

- example.init(argument:Int, another:String)
- example.subscript(index:Int)

Maybe with ‘#’ too
- example.init#argument:Int#another:String
- example.init#argument#another
- example.init#(argument:Int, another:String)
- example.subscript#index:Int
- example.subscript#Int

Pierre

Le 14 déc. 2015 à 08:57, ilya via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

> Being able to refer to getters and setters is a good idea and aligns with being able to refer to initializers and methods.
> I would also add subscripts to the list if possible.

Great idea! Let's discuss syntax

How about
- example.get.member
- example.set.member
- example.init(argument:Int, another:String)
- example.subscript(index:Int)

On Mon, Dec 14, 2015 at 3:49 AM, Marc Knaup via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Wait, where is stated that KVO is a long-term goal for Swift? I might have missed that.

I find that one of Objective-C's most annoying features. It makes it really difficult to reason about code when things can happen unexpectedly left and right. It's the same issue with aspect-oriented programming.

I prefer explicit integration points like closures, delegates and alike.
Most times I used KVO in the past was to work around bugs or annoyances on iOS, like for example forcing a button stay enabled even when iOS disables it.

Also it's unlikely that all mutable properties will support observation automatically. That would require the optimizer to keep using dynamic dispatch for all of them which will hurt performance.

But I'm getting off-topic since your discussion is not about KVO nor about KVC.

Being able to refer to getters and setters is a good idea and aligns with being able to refer to initializers and methods.
I would also add subscripts to the list if possible.

On Mon, Dec 14, 2015 at 1:34 AM, Michael Henson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Swift-like full KVO/KVC as in Objective-C is a stated long-term goal for Swift's evolution. The 90% solution might be more straightforward:

class Example {
  var member: String

  func print() {
    print(self.member)
  }
}

var example = Example(member: "Hi!")

var example_print_method = example.print
example_print_method()
result:
Hi!

If there were a mechanism for referring to the getter and setter methods on the var member property as the same kind of self-capturing closures, it could make simple cases of data binding easier to implement:

var serializeFields = [
  "member": example.member#get,
]

var deserializeFields = [
  "member": example.member#set,
]

var broadcastValueTo = [
  "memberValues": [
     example.member#set,
     example2.member#set,
     example3.member#set,
  ]
]

viewController.textField.onValueChanged(example.member#set)

Etc.

The "#" notation is just a placeholder for "whatever mechanism is decided upon", though it does seem to be available and using it postfix makes a first-glance sense to me in terms of the semantics of expressions.

Mike

_______________________________________________
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


(Douglas Gregor) #11

FYI, I just sent a proposal draft titled “Generalized Naming for Any Function” that pulls these ideas together more formally. I went with a different syntax that I’d been kicking around for a while internally, and I’d love to hear everyone’s thoughts on this.

  - Doug

···

On Dec 14, 2015, at 12:25 AM, Pierre Monod-Broca via swift-evolution <swift-evolution@swift.org> wrote:

+1

I like the #get, #set suffixes.

I’m afraid the following would be a bit ambiguous

- example.init(argument:Int, another:String)
- example.subscript(index:Int)

Maybe with ‘#’ too
- example.init#argument:Int#another:String
- example.init#argument#another
- example.init#(argument:Int, another:String)
- example.subscript#index:Int
- example.subscript#Int

Pierre

Le 14 déc. 2015 à 08:57, ilya via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

> Being able to refer to getters and setters is a good idea and aligns with being able to refer to initializers and methods.
> I would also add subscripts to the list if possible.

Great idea! Let's discuss syntax

How about
- example.get.member
- example.set.member
- example.init(argument:Int, another:String)
- example.subscript(index:Int)

On Mon, Dec 14, 2015 at 3:49 AM, Marc Knaup via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Wait, where is stated that KVO is a long-term goal for Swift? I might have missed that.

I find that one of Objective-C's most annoying features. It makes it really difficult to reason about code when things can happen unexpectedly left and right. It's the same issue with aspect-oriented programming.

I prefer explicit integration points like closures, delegates and alike.
Most times I used KVO in the past was to work around bugs or annoyances on iOS, like for example forcing a button stay enabled even when iOS disables it.

Also it's unlikely that all mutable properties will support observation automatically. That would require the optimizer to keep using dynamic dispatch for all of them which will hurt performance.

But I'm getting off-topic since your discussion is not about KVO nor about KVC.

Being able to refer to getters and setters is a good idea and aligns with being able to refer to initializers and methods.
I would also add subscripts to the list if possible.

On Mon, Dec 14, 2015 at 1:34 AM, Michael Henson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Swift-like full KVO/KVC as in Objective-C is a stated long-term goal for Swift's evolution. The 90% solution might be more straightforward:

class Example {
  var member: String

  func print() {
    print(self.member)
  }
}

var example = Example(member: "Hi!")

var example_print_method = example.print
example_print_method()
result:
Hi!

If there were a mechanism for referring to the getter and setter methods on the var member property as the same kind of self-capturing closures, it could make simple cases of data binding easier to implement:

var serializeFields = [
  "member": example.member#get,
]

var deserializeFields = [
  "member": example.member#set,
]

var broadcastValueTo = [
  "memberValues": [
     example.member#set,
     example2.member#set,
     example3.member#set,
  ]
]

viewController.textField.onValueChanged(example.member#set)

Etc.

The "#" notation is just a placeholder for "whatever mechanism is decided upon", though it does seem to be available and using it postfix makes a first-glance sense to me in terms of the semantics of expressions.

Mike

_______________________________________________
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


(Tino) #12

Of course, if you’re worried about the performance costs associated with that extra method call, you might want to include a keyword, such as “observable”, and only generate the method call(s) if that keyword is on the property.

I strongly agree that Swift should have/keep a possibility to create properties with no performance penalty — but I guess comfort is more important, so I'd rather make observable the default and offer a possibility to disable it.

Tino


(Javier Soto) #13

One thing to be aware of is the lifetime semantics. This is something that
has bit me in the past when using object.functionName and passing that to
another object that holds on the function: it will actually hold a strong
reference to object! So it's easy to see how one can create retain cycles
that way, and it's not obvious at all when reading the code (IMO)

···

On Wed, Dec 16, 2015 at 1:07 AM Adrian Kashivskyy via swift-evolution < swift-evolution@swift.org> wrote:

+1, I like this idea! I'm not sure if I like `#`, though – maybe the type
should be inferred, much like when using `init`s?

struct Foo {
init(_: Int) {}
init(_: String) {}
}

// this infers the int setter
let intInit: (Int) -> Foo = Foo.init

// this infers the string setter
let stringInit: (String) -> Foo = Foo.init

Note that you cannot explicitly refer to a specific `init`. My proposal is
to use the same technique when referring to getters and setters:

struct Foo {
let bar: Int
}

// this just reads the value
let value = Foo.bar

// this infers a getter
let getter: () -> Int = Foo().bar

// this infers a setter
let setter: (Int) -> Void = Foo().bar

Pozdrawiam – Regards,
Adrian Kashivskyy

Wiadomość napisana przez Pierre Monod-Broca via swift-evolution <
swift-evolution@swift.org> w dniu 14.12.2015, o godz. 09:25:

+1

I like the #get, #set suffixes.

I’m afraid the following would be a bit ambiguous

- example.init(argument:Int, another:String)

- example.subscript(index:Int)

Maybe with ‘#’ too
- example.init#argument:Int#another:String
- example.init#argument#another
- example.init#(argument:Int, another:String)
- example.subscript#index:Int
- example.subscript#Int

Pierre

Le 14 déc. 2015 à 08:57, ilya via swift-evolution < > swift-evolution@swift.org> a écrit :

> Being able to refer to getters and setters is a good idea and aligns
with being able to refer to initializers and methods.
> I would also add subscripts to the list if possible.

Great idea! Let's discuss syntax

How about
- example.get.member
- example.set.member
- example.init(argument:Int, another:String)
- example.subscript(index:Int)

On Mon, Dec 14, 2015 at 3:49 AM, Marc Knaup via swift-evolution < > swift-evolution@swift.org> wrote:

Wait, where is stated that KVO is a long-term goal for Swift? I might
have missed that.

I find that one of Objective-C's most annoying features. It makes it
really difficult to reason about code when things can happen unexpectedly
left and right. It's the same issue with aspect-oriented programming.

I prefer explicit integration points like closures, delegates and alike.
Most times I used KVO in the past was to work around bugs or annoyances
on iOS, like for example forcing a button stay enabled even when iOS
disables it.

Also it's unlikely that all mutable properties will support observation
automatically. That would require the optimizer to keep using dynamic
dispatch for all of them which will hurt performance.

But I'm getting off-topic since your discussion is not about KVO nor
about KVC.

Being able to refer to getters and setters is a good idea and aligns with
being able to refer to initializers and methods.
I would also add subscripts to the list if possible.

On Mon, Dec 14, 2015 at 1:34 AM, Michael Henson via swift-evolution < >> swift-evolution@swift.org> wrote:

Swift-like full KVO/KVC as in Objective-C is a stated long-term goal for
Swift's evolution. The 90% solution might be more straightforward:

class Example {
  var member: String

  func print() {
    print(self.member)
  }
}

var example = Example(member: "Hi!")

var example_print_method = example.print
example_print_method()
result:
Hi!

If there were a mechanism for referring to the getter and setter methods
on the var member property as the same kind of self-capturing closures, it
could make simple cases of data binding easier to implement:

var serializeFields = [
  "member": example.member#get,
]

var deserializeFields = [
  "member": example.member#set,
]

var broadcastValueTo = [
  "memberValues": [
     example.member#set,
     example2.member#set,
     example3.member#set,
  ]
]

viewController.textField.onValueChanged(example.member#set)

Etc.

The "#" notation is just a placeholder for "whatever mechanism is
decided upon", though it does seem to be available and using it postfix
makes a first-glance sense to me in terms of the semantics of expressions.

Mike

_______________________________________________
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

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

--
Javier Soto


(Charles Srstka) #14

The problem, as I see it, is that KVO is not useful unless the author has specifically thought about it, and if “observable” is not the default, but something that the author of the class had to add, this demonstrates that the author *has* considered KVO compliance for the property. Without some way to know that the property has deliberately been made KVO compliant, code that observes the property cannot be reliable. Therefore, I’d suggest *not* making observable the default, as it ultimately makes KVO a lot more useful.

Example:

class MyObject {
  var foo: Int { get } // This is a computed property, possibly dependent on something else. Can I safely observe it and expect it to work?

  var bar: Int // This is a stored property—but do I know it won’t be changed to a computed property in the future? Can I observe this and trust my code won’t break in version 2.0?
}

vs.

class MyObject {
  observable var foo: Int { get } // YES I can safely observe this.

  observable var bar // YES I can safely observe this.
}

Observing things that aren’t observable is fraught with peril (in the current Objective-C implementation, it can often lead to crashes via exceptions being thrown). Knowing that it’s safe is valuable—I’d even say essential. Currently you have to look in the documentation, which as we all know isn’t always complete or up to date. Having the keyword there shows, right in the interface, that the author has committed to making this property compliant and keeping it that way in future releases.

The observable keyword could also allow one to set the KVO key string to something other than just the name of the property:

class MyObject {
  observable(somethingElse) var something: Int
}

You’d also need an annotation to tell the system which other key paths the property is dependent upon, which I’d probably do something like this:

class MyObject {
  observable var foo: Int
  observable var bar: Int {
    get { return self.foo }
    set(bar) { self.foo = bar }
    depends { return [“foo”] }
  }
}

The compiler could automatically add a CollectionType property to the class corresponding to each property, and then rewrite the property setter something like this (pseudocode):

class MyObject {
  private var observersOfFoo: [ObserverProtocol]?

  observable var foo: Int {
    set(newValue) {
      let oldValue = _foo

      _foo = newValue // or whatever the default setter usually does

      self.observersOfFoo?.forEach { $0.notifyKeyValueChanged(self, key: “foo”, oldValue: oldValue) }
    }
  }
}

I made it optional so that for the common case where there aren’t actually any observers on the property, the only performance costs are the store of the old value and checking an optional. Since optionals are basically enums, which are represented as an 8-bit integer which in this case can have the values 0 or 1, I’d expect checking an optional to have similar performance characteristics to checking a boolean, and thus I’d expect it to perform better than checking whether an array is empty, and doing some quick tests seems to back that up.

Charles

···

On Dec 27, 2015, at 4:23 AM, Tino Heth <2th@gmx.de> wrote:

Of course, if you’re worried about the performance costs associated with that extra method call, you might want to include a keyword, such as “observable”, and only generate the method call(s) if that keyword is on the property.

I strongly agree that Swift should have/keep a possibility to create properties with no performance penalty — but I guess comfort is more important, so I'd rather make observable the default and offer a possibility to disable it.

Tino