[Review] SE-0030 Property Behaviors

I'm having trouble wrapping my head around the difference between accessors and methods defined by a property: AFAIU accessors are like abstract methods if required and just like methods if not, whereas methods are like final methods as they cannot be overridden in a property use site.

Accessors are provided by the var declaration using the behavior. Methods are fixed implementations.

-Joe

···

On Feb 19, 2016, at 7:39 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:

If I did understand this correctly then I'd prefer that instead of "accessor" we would just use "func" and introduce a new keyword "abstract". The latter can then be extended to classes in another proposal.

-Thorsten

Am 19.02.2016 um 03:56 schrieb Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

Based on review feedback, I've revised the declaration syntax proposal for property behaviors to be more in line with our other declaration forms, reverting to the earlier pre-review "var behavior" proposal. I've updated the proposal in swift-evolution:

https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md

In discussion with the core team, we've also strongly come in favor of applying behaviors to properties using attribute syntax, e.g.:

@lazy var x = 111
@delayed var x: Int

They're definitely attribute-like, and we think it makes sense for behaviors to be the first of hopefully many kinds of user-defined behaviors. What do you all think of this direction?

-Joe

On Feb 10, 2016, at 2:00 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello Swift community,

The review of SE-0030 "Property Behaviors" begins now and runs through February, 2016. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md <https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-proposal.md&gt;
Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

https://lists.swift.org/mailman/listinfo/swift-evolution
or, if you would like to keep your feedback private, directly to the review manager. When replying, please try to keep the proposal link at the top of the message:

Proposal link:

https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md
Reply text

Other replies
<GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

What is your evaluation of the proposal?
Is the problem being addressed significant enough to warrant a change to Swift?
Does this proposal fit well with the feel and direction of Swift?
If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md
Thank you,

Doug Gregor

Review Manager

_______________________________________________
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

Response inline below...

In discussion with the core team, we've also strongly come in favor of applying behaviors to properties using attribute syntax, e.g.:

@lazy var x = 111
@delayed var x: Int

They're definitely attribute-like, and we think it makes sense for behaviors to be the first of hopefully many kinds of user-defined behaviors. What do you all think of this direction?

Are they though? We’ve been discussing this a lot in the thread on enforcing super method requirements; while my preference in that case is for an attribute, I feel it is appropriate there because they’re more like directives and informative, and will generate warnings (and possibly errors too) in the same way as @warn_unused_result does. A lot of other attributes are either informational or are produce some kind of restriction that the compiler warns us about (or errors on).

I think Haravikk makes a good point here. Currently, the `@` symbol seems like a holding ground for miscellaneous compiler directives and backwards compatibility issues (e.g., @objc, @IBOutlet). So from this view, putting behaviors, which are a forward looking, swift native idea, under the ‘@‘ symbol, seems debatable.

I don't think that was ever our long term intent for `@`. We always intended to open the space up to user annotations at some point.

The syntax Haravikk proposes below makes sense to me. Does it cause big problems from a compiler implementer’s standpoint?

It could be made to work today. 'var' <identifier> <pattern>' isn't currently a valid production. It would however interfere with the potential future ability to destructure structs or classes in 'var' bindings; we could conceivably allow `var CGPoint(x: x, y: y) = point` or something like it in the broad future.

-Joe

···

On Feb 19, 2016, at 8:30 AM, Matt Whiteside <mwhiteside.dev@gmail.com> wrote:

On Feb 19, 2016, at 06:14, Haravikk via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 19 Feb 2016, at 02:56, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Matt

However, property behaviours are more like defining protocols for properties, which is clearly very different from an attribute, and IMO not really compiler magic either. I think a keyword makes most sense, such as behaviour(lazy), though personally I don’t see why we can’t just include the names directly, i.e:

  var lazy x = 111

Isn’t ambiguous, because the right most token (x) is used as the name, var is an explicitly defined keyword, therefore everything else (lazy) can be looked up as a behaviour, in much the same way as types would be. I know there’s some risk of naming collision, but I don’t think it’s all that high, and if property behaviours are functional enough there should be no reason to add any new keywords for use on properties in future as they will be added as behaviours in the standard library. So long as they’re a way to disambiguate your property behaviours from any in the standard library (which will be needed anyway) then I think it’s fine, even when you’re dealing with stuff like:

  static final internal var lazy synchronized x = 111

If we require the order to be:

  [static, final, private|internal|public] [var|let] [behaviours…] [name]

Then I don’t think there should be any real problems. This may even already be how it is, I’m not sure as this is how I structure them anyway.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

I'm having trouble wrapping my head around the difference between accessors and methods defined by a property: AFAIU accessors are like abstract methods if required and just like methods if not, whereas methods are like final methods as they cannot be overridden in a property use site.

Accessors are more like property requirements: they're meant to be customization points, but you can provide a default implementation. Methods defined in a property are for (a) code organization and (b) eventually, exposing additional functionality related to the property to users. No customization allowed.

If I did understand this correctly then I'd prefer that instead of "accessor" we would just use "func" and introduce a new keyword "abstract". The latter can then be extended to classes in another proposal.

I don't think "abstract" is the right keyword to use, but I do agree that "accessor" might not be the perfect term for this feature. Not sure what would be better, though.

···

--
Brent Royal-Gordon
Architechies

Response inline below...

In discussion with the core team, we've also strongly come in favor of applying behaviors to properties using attribute syntax, e.g.:

@lazy var x = 111
@delayed var x: Int

They're definitely attribute-like, and we think it makes sense for behaviors to be the first of hopefully many kinds of user-defined behaviors. What do you all think of this direction?

Are they though? We’ve been discussing this a lot in the thread on enforcing super method requirements; while my preference in that case is for an attribute, I feel it is appropriate there because they’re more like directives and informative, and will generate warnings (and possibly errors too) in the same way as @warn_unused_result does. A lot of other attributes are either informational or are produce some kind of restriction that the compiler warns us about (or errors on).

I think Haravikk makes a good point here. Currently, the `@` symbol seems like a holding ground for miscellaneous compiler directives and backwards compatibility issues (e.g., @objc, @IBOutlet). So from this view, putting behaviors, which are a forward looking, swift native idea, under the ‘@‘ symbol, seems debatable.

I don't think that was ever our long term intent for `@`. We always intended to open the space up to user annotations at some point.

The syntax Haravikk proposes below makes sense to me. Does it cause big problems from a compiler implementer’s standpoint?

It could be made to work today. 'var' <identifier> <pattern>' isn't currently a valid production. It would however interfere with the potential future ability to destructure structs or classes in 'var' bindings; we could conceivably allow `var CGPoint(x: x, y: y) = point` or something like it in the broad future.

Thanks for explaining this. I hadn’t thought of that use case.

I’m not so much concerned with whether the `@` symbol is internal to the compiler, but rather with lumping together behaviors, which I could see becoming a very mainstream feature relevant to application code, with stuff like @inline, @asmname, @transparent, and other somewhat obscure compiler hints.

Matt

···

On Feb 19, 2016, at 10:53, Joe Groff <jgroff@apple.com> wrote:

On Feb 19, 2016, at 8:30 AM, Matt Whiteside <mwhiteside.dev@gmail.com <mailto:mwhiteside.dev@gmail.com>> wrote:

On Feb 19, 2016, at 06:14, Haravikk via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 19 Feb 2016, at 02:56, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-Joe

Matt

However, property behaviours are more like defining protocols for properties, which is clearly very different from an attribute, and IMO not really compiler magic either. I think a keyword makes most sense, such as behaviour(lazy), though personally I don’t see why we can’t just include the names directly, i.e:

  var lazy x = 111

Isn’t ambiguous, because the right most token (x) is used as the name, var is an explicitly defined keyword, therefore everything else (lazy) can be looked up as a behaviour, in much the same way as types would be. I know there’s some risk of naming collision, but I don’t think it’s all that high, and if property behaviours are functional enough there should be no reason to add any new keywords for use on properties in future as they will be added as behaviours in the standard library. So long as they’re a way to disambiguate your property behaviours from any in the standard library (which will be needed anyway) then I think it’s fine, even when you’re dealing with stuff like:

  static final internal var lazy synchronized x = 111

If we require the order to be:

  [static, final, private|internal|public] [var|let] [behaviours…] [name]

Then I don’t think there should be any real problems. This may even already be how it is, I’m not sure as this is how I structure them anyway.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

First a general question: Are these behaviors also allowed on normal variables in function bodies (regarding the current proposal)?

···

----------

The "initialValue" should be exposed as closure/function since it can introduce side effects:

        var [resettable] y = functionWithSideEffects()

According to your proposal: "If the behavior includes an initial value requirement declaration, then the identifier initialValue is bound as a get-only computed property that evaluates the initial value expression for the property"

So if I understand it right if I reset "y" "functionWithSideEffects" gets executed.

------------

Can you explain what is the difference between "Self" and "Value" in the following example?:

protocol Fungible {
        typealias Fungus
        func funge() -> Fungus
}

var behavior runcible<Value where Self: Fungible, Self.Fungus == Value>: Value {
        get {
                return self.funge()
        }
}

Isn't "Self" the same as "Value"? So it can be rewritten to:

var behavior runcible<Value: Fungible, Value.Fungus == Value>: Value {
        get {
                return self.funge()
        }
}

----------

You've wrote that behaviors shouldn't be types/type-like e.g. "var x: lazy<Int>".
Can you mention some disadvantages?

I can't see huge ones. However I don't see any advantages.

Is there any advantage regarding a type-like behavior?

---------

I just remembered recursive value types...
We can even eliminate another keyword: "indirect"

implementation:

var behavior indirect<Value>: Value {
        class Ref<T> {
                var value: T
                init(_ value: T) { self.value = value }
        }

        var reference: Ref<Value> = Ref(initialValue())
        get { return reference.value }
        set { reference.value = newValue }
}

I'm glad you made it so far :)
- Maximilian

I think the whole space of out-of-band meta-operations deserves its own separate discussion. In addition to your concerns, exposing metaoperations as interface also introduces bigger concerns about resilience, protocol conformance, etc. that deserve deeper consideration.

The way I see it, those meta-operations are just functions enclosed inside the variable's namespace. So in a protocol, and from an API point of view, they'd look like this:

  protocol MyCounter {
    var count: Int {
      get
      set
      func reset()
    }
  }

Here, you don't need to know that `reset` is provided by a particular behavior. That is just an implementation detail.

I find your behavior proposal lacking in that regard. A behavior contains both the interface and the implementation of those meta-operations. It shouldn't. If you want to implement @resettable differently for one of the variables, that should not be visible to the outside world. The default implementation of @resettable shouldn't be the only one allowed.

It's interesting that your current implementation uses a protocol with a protocol extension to define behaviors, because the more I think about behaviors the more I believe they should be like a protocol and provide only the interface. The above could be reformulated like this:

  protocol Resettable {
    func reset()
  }
  protocol MyCounter {
    @Resettable var count: Int { get set }
  }

As I noted in your pre-review comments, trying to separate storage control from observers doesn't seem like a net simplification to me. If you try to extend either feature on its own, you end up encroaching in the other's space. A behavior that manipulates storage may need per-declaration hooks, which accessor provides. An accessor may need to introduce bookkeeping storage.

An "accessor hook" is not at all the same thing as an "observer" like `willSet` in my mind. A hook from a behavior is more like requirement of something that must be provided. You are proposing that this requirement be expressed using a syntax similar observers like `willSet`, but I'm not sure reusing the same syntax it's the right thing to do.

If a behavior was a protocol, it could do what a protocol is good at: define requirements (hooks) and leave those requirements to be implemented by the property definition. You could then implement them in the property definition itself:

  protocol Resettable {
    func reset()
  }
  @Resettable var count: Int {
    func reset() { count = 0 }
  }

And if a behavior was a protocol, then you could also provide a default implemenation as a protocol extension. Here I'll make the protocol conform to a magic `eager var` protocol that makes available the init value for protocol extensions:

  protocol Resettable: eager var {
    func reset()
  }
  extension Resettable {
    // `value` accessible because this protocol inherits from `var`
    // `evalInitValue` accessible here because this protocol inherits from `eager var`
    func reset() { value = evalInitValue() }
  }
  @Resettable var count: Int

And you could allow the behavior to be something else than a protocol too. For instance, allow it to be a struct if you need to implement your own storage:

  struct DelayedStorage<Value> {
    var storage: Value?
    var value: Value {
      get {
        guard let theValue = storage else {
          fatalError("delayedImmutable property read before initialization")
        }
        return theValue
      }
      set {
        guard storage == nil else {
          fatalError("delayedImmutable property rewritten after initialization")
        }
        storage = newValue
      }
    }

    init() {
      storage = nil
    }
  }
  @DelayedStorage var outlet: UIView

And if you need access to the initial value within the struct, you can make the struct inherit from `deferred var` or `eager var` which would make the initial value accessible as an inherited member:

  struct Lazy<Value>: deferred var {
    var storage: Value?
    var value: Value {
      mutating get {
        guard let theValue = storage else {
          // evalInitValue accessible because this struct inherits from `eager var`
          storage = evalInitValue()
        }
        return theValue
      }
      set {
        storage = newValue
      }
    }

    // does not allow initialization with a value (no constructor for it)
    init() {
      storage = nil
    }
  }
  @Lazy var processorCount: Int = NSProcessInfo.processInfo().processorCount

If a struct or a protocol inherit from `var`, then its methods have access to the outer context (the scope the var lives in if it's a struct or a class). That scope would be exposed through the `context` member also inherited from `var`. And to better make use of it, you should also be able to constrain the context the `var` lives in:

  protocol Synchronizable {
    func withLock<T>(@noescape task: () -> T) -> T
  }
  struct Synchronized<Value>: var in Synchronizable {
    var storage: Value
    var value: Value {
      get {
        context.withLock {
          return storage
        }
      }
      set {
        context.withLock {
          storage = newValue
        }
      }
    }

    init(_ initValue: Value) {
      storage = initValue
    }
  }
  @Synchronized var faultCount: Int = 0

Using a mix of protocols and structs for behaviors allows protocols to define the interface while a struct and/or extensions and/or the property declaration can provide the implementation. All this gives a lot of flexibility in how to implement what is exposed in the interface.

So, to summarize, that would decompose property behaviors in a couple of smaller features:

1. The ability to use a struct as a wrapper for a property's value: the `value` property of the struct becomes the property's value and other members are accessible using an out-of-band member access operator.
2. The ability for a property to define out-of-band members (`var`s `let`s, and `func`s) inline inside the property declaration (like a custom `reset` function) that can be accessed using the out-of-band member access operator.
3. The ability to have a property conform to a protocol that either the storage struct, a protocol extension, or the inline out-of-band members defined in the property must implement.
4. The ability for a protocol or struct to inherit from `var`, which would add the `value` and `context` members. The `evalInitValue` member would only be available for `deferred var` or `eager var`, and in the case of `deferred var` not available in the constructor (because it might require `self` from the outer context).
5. Observers, like `willSet`, `willChange`, etc. can be implemented as a separate `observer` construct that can be used on any property simply by writing the observer inside the property declaration. (As discussed in my previous email.)

There's something else interesting with this type-based approach. Take note of how the `DelayedStorage` struct above does not inherit from `var`. That's because DelayedStorage does not need access to the outer context or `evalInitValue()`. And this makes `DelayedStorage` a perfectly valid struct to use elsewhere, such as:

  var delayedObjects: [DelayedStorage<NSObject>]

You could implement Atomic, NSCopying, and many other behaviors this way and be able to reuse them elsewhere.

And, just teasing... but maybe there's a way a behavior could be attached as a type modifier instead of a property modifier. This would allow you to write `var delayedObjects: [@DelayedStorage NSObject]` and not have to access the value by appending `.value` every time.

···

Le 15 févr. 2016 à 17:55, Joe Groff <jgroff@apple.com> a écrit :

--
Michel Fortin
https://michelf.ca

+1 for both the revised proposal and Austin's comments re @ and #. I was
giving a talk about Swift Evolution at the local Cocoa Heads meet up and a
question from the floor was what was the difference between @ and #? I
foundered a bit answering the question which shows I don't know the answer.
So clarity would be good for me.

···

On Friday, 19 February 2016, Austin Zheng via swift-evolution < swift-evolution@swift.org> wrote:

In discussion with the core team, we've also strongly come in favor of
applying behaviors to properties using attribute syntax, e.g.:

@lazy var x = 111
@delayed var x: Int

They're definitely attribute-like, and we think it makes sense for
behaviors to be the first of hopefully many kinds of user-defined
behaviors. What do you all think of this direction?

Seems like a good idea.

It would be great if we could eventually nail down 'recommended semantics'
for symbols like @, #, &, etc, and then normalize the language syntax to
match. We have a couple of informal conventions emerging, but I find that
(e.g.) trying to figure out why Language Feature X has a leading '@' rather
than being a keyword is still rather difficult.

--
-- Howard.

I'm having trouble wrapping my head around the difference between accessors and methods defined by a property: AFAIU accessors are like abstract methods if required and just like methods if not, whereas methods are like final methods as they cannot be overridden in a property use site.

Accessors are provided by the var declaration using the behavior. Methods are fixed implementations.

Thanks! So accessors are indeed like abstract methods (if required) and methods are like final methods.

If I did understand this correctly then I'd prefer that instead of "accessor" we would just use "func" and introduce a new keyword "abstract". The latter can then be extended to classes in another proposal.

i.e. instead of a required "accessor" we would use "abstract func" and instead of an "accessor" with a default implementation we would use "func".
Instead of "func" for methods we would use "final func".

Then the only new concept would be "abstract" instead of "accessor" and we could extend it to normal methods which would be welcome.

-Thorsten

···

Am 19.02.2016 um 19:39 schrieb Joe Groff <jgroff@apple.com>:

On Feb 19, 2016, at 7:39 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:

Am 19.02.2016 um 03:56 schrieb Joe Groff via swift-evolution <swift-evolution@swift.org>:

Based on review feedback, I've revised the declaration syntax proposal for property behaviors to be more in line with our other declaration forms, reverting to the earlier pre-review "var behavior" proposal. I've updated the proposal in swift-evolution:

https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md

In discussion with the core team, we've also strongly come in favor of applying behaviors to properties using attribute syntax, e.g.:

@lazy var x = 111
@delayed var x: Int

They're definitely attribute-like, and we think it makes sense for behaviors to be the first of hopefully many kinds of user-defined behaviors. What do you all think of this direction?

-Joe

On Feb 10, 2016, at 2:00 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Hello Swift community,

The review of SE-0030 "Property Behaviors" begins now and runs through February, 2016. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md
Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

https://lists.swift.org/mailman/listinfo/swift-evolution
or, if you would like to keep your feedback private, directly to the review manager. When replying, please try to keep the proposal link at the top of the message:

Proposal link:

https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md
Reply text

Other replies
What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

What is your evaluation of the proposal?
Is the problem being addressed significant enough to warrant a change to Swift?
Does this proposal fit well with the feel and direction of Swift?
If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md
Thank you,

Doug Gregor

Review Manager

_______________________________________________
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

Response inline below...

In discussion with the core team, we've also strongly come in favor of applying behaviors to properties using attribute syntax, e.g.:

@lazy var x = 111
@delayed var x: Int

They're definitely attribute-like, and we think it makes sense for behaviors to be the first of hopefully many kinds of user-defined behaviors. What do you all think of this direction?

Are they though? We’ve been discussing this a lot in the thread on enforcing super method requirements; while my preference in that case is for an attribute, I feel it is appropriate there because they’re more like directives and informative, and will generate warnings (and possibly errors too) in the same way as @warn_unused_result does. A lot of other attributes are either informational or are produce some kind of restriction that the compiler warns us about (or errors on).

I think Haravikk makes a good point here. Currently, the `@` symbol seems like a holding ground for miscellaneous compiler directives and backwards compatibility issues (e.g., @objc, @IBOutlet). So from this view, putting behaviors, which are a forward looking, swift native idea, under the ‘@‘ symbol, seems debatable.

I don't think that was ever our long term intent for `@`. We always intended to open the space up to user annotations at some point.

The syntax Haravikk proposes below makes sense to me. Does it cause big problems from a compiler implementer’s standpoint?

It could be made to work today. 'var' <identifier> <pattern>' isn't currently a valid production. It would however interfere with the potential future ability to destructure structs or classes in 'var' bindings; we could conceivably allow `var CGPoint(x: x, y: y) = point` or something like it in the broad future.

As that's something I'd like to have sometime, I wouldn't want to block that path.

-Thorsten

···

Am 19.02.2016 um 19:53 schrieb Joe Groff via swift-evolution <swift-evolution@swift.org>:

On Feb 19, 2016, at 8:30 AM, Matt Whiteside <mwhiteside.dev@gmail.com> wrote:

On Feb 19, 2016, at 06:14, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:
On 19 Feb 2016, at 02:56, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

-Joe

Matt

However, property behaviours are more like defining protocols for properties, which is clearly very different from an attribute, and IMO not really compiler magic either. I think a keyword makes most sense, such as behaviour(lazy), though personally I don’t see why we can’t just include the names directly, i.e:

  var lazy x = 111

Isn’t ambiguous, because the right most token (x) is used as the name, var is an explicitly defined keyword, therefore everything else (lazy) can be looked up as a behaviour, in much the same way as types would be. I know there’s some risk of naming collision, but I don’t think it’s all that high, and if property behaviours are functional enough there should be no reason to add any new keywords for use on properties in future as they will be added as behaviours in the standard library. So long as they’re a way to disambiguate your property behaviours from any in the standard library (which will be needed anyway) then I think it’s fine, even when you’re dealing with stuff like:

  static final internal var lazy synchronized x = 111

If we require the order to be:

  [static, final, private|internal|public] [var|let] [behaviours…] [name]

Then I don’t think there should be any real problems. This may even already be how it is, I’m not sure as this is how I structure them anyway.
_______________________________________________
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

I'm having trouble wrapping my head around the difference between accessors and methods defined by a property: AFAIU accessors are like abstract methods if required and just like methods if not, whereas methods are like final methods as they cannot be overridden in a property use site.

Accessors are more like property requirements: they're meant to be customization points, but you can provide a default implementation. Methods defined in a property are for (a) code organization and (b) eventually, exposing additional functionality related to the property to users. No customization allowed.

If I did understand this correctly then I'd prefer that instead of "accessor" we would just use "func" and introduce a new keyword "abstract". The latter can then be extended to classes in another proposal.

I don't think "abstract" is the right keyword to use, but I do agree that "accessor" might not be the perfect term for this feature. Not sure what would be better, though.

Why? "abstract" is quite common for denoting a method requirement, so I think it is quite appropriate here.

-Thorsten

···

Am 19.02.2016 um 21:34 schrieb Brent Royal-Gordon <brent@architechies.com>:

--
Brent Royal-Gordon
Architechies

Sure, that's definitely a suite of functionality that could be factored into its own discussion.

-Joe

···

On Feb 11, 2016, at 11:26 AM, Jonathan Tang via swift-evolution <swift-evolution@swift.org> wrote:

How about contractions of the proposal then? :-)

The only part of the existing proposal that my brainstorm last night actually changed (as opposed to extended) was the need for behavior-added methods on properties and a syntax for calling them (the foo.[lazy].clear() case). This also seems to be one of the more contentious parts in the discussion here, and appears to be non-critical in the use-cases listed in the proposal. So +1 to the proposal itself, -1 to the ability to add methods to properties and call them, with the latter perhaps separated out into a future extension. +1 for keeping the underbar in the behavior definition syntax, or even explicitly binding it to a string literal; it seems quite likely this will be useful.

I'd prefer not to take it as a keyword. I think we can parse it contextually between 'var' and another identifier, even though we don't do that anywhere else yet.

If we really want to keep the initial proposal modest, we could subset out the declaration syntax bikeshedding and start with the lazy implementer's approach, exposing the unpainted protocol underlying the behavior:

@property_behavior
protocol behavior {
  // Type of the property instantiating the behavior.
  associatedtype Value
  // Backing storage for the behavior.
  var storage: Value? { get set }
}
extension behavior {
  // Initializer for the instantiated storage.
  static func initStorage() -> Value? {
    return nil
  }
  // Property implementation.
  var value: Value {
    get { ... }
    set { ... }
  }
}

-Joe

···

On Feb 11, 2016, at 12:53 PM, Chris Lattner <clattner@apple.com> wrote:

I’m very curious where you stand on the syntax of the behavior decl, because this decl (as one concrete example) seems like it would be *much* nicer as:

public var behavior changeObserved<Value : Equatable> {

Where [lazy] is currently used, could the syntax instead be #behavior(lazy)? That prevents a possible future naming clash, keeps the # meaning compiler-magic, and doesn't use the , which is contentious.

I think that if we go down this road, @behavior(lazy) or just @lazy is strictly superior. We already have the @ sigil for attributes; we don't need to introduce another sigil for no apparent reason.

(But unless we're going to use the latter syntax and say "all @s are behaviors, we just haven't formalized func/type/etc. behaviors yet" so we finally have an idea of what @ means, I don't think either of these syntaxes is better than the one proposed.)

···

--
Brent Royal-Gordon
Architechies

From what I've seen @ is used for annotations, which apply to declarations.

I've never seen them used as an attribute like foo.@bar.

foo.#behavior(lazy).clear() seems clearer than foo.[lazy].clear().

···

On Thu, Feb 11, 2016 at 4:36 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

> Where [lazy] is currently used, could the syntax instead be
#behavior(lazy)? That prevents a possible future naming clash, keeps the #
meaning compiler-magic, and doesn't use the , which is contentious.

I think that if we go down this road, @behavior(lazy) or just @lazy is
strictly superior. We already have the @ sigil for attributes; we don't
need to introduce another sigil for no apparent reason.

(But unless we're going to use the latter syntax and say "all @s are
behaviors, we just haven't formalized func/type/etc. behaviors yet" so we
finally have an idea of what @ means, I don't think either of these
syntaxes is better than the one proposed.)

--
Brent Royal-Gordon
Architechies

--
Trent Nadeau

I’m sorry if this has already been discussed, but what are the drawbacks of putting the variable's behaviors before the ‘var’ keyword? Like this:

lazy synchronized var x:SomeType

That seems pretty ideal from a readability standpoint.

Matt

···

On Feb 14, 2016, at 05:05, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:

• Angle brackets already appear in var declarations for generic types; that means there are two different meanings for angle brackets in the same construct.

Isn't the same true when you declare an array (or a closure)?

• When we eventually allow you to apply multiple behaviors to a single property, that will also mean that *commas* are used in both of those angle bracket constructs, but with different meanings (one means "chain these", the other means "fill these two slots").

True, but imho also no deal breaker; I would like to have labeled generic parameters anyway ;-)
Afaics, it isn't decided how multiple behaviors will be handled yet.

These are not fatal errors, but they're also completely unforced—either `` or `{}` would not have this problem. So why choose the option that has the problem?

Because those have a similar (and imho bigger) problems:
Grouping blocks of code or declaring arrays are things that are tightly coupled with "their" braces, and for me, "<>" causes the smallest disruption… arrays, capture lists and blocks have little in common with behaviors, but property behaviors could be expressed using generics*

Tino

* thinking of something like

protocol Behavior {
  typealias ValueType
  var value: ValueType { get set }
}

class DefaultBehavior<T> {
  typealias ValueType = T

  var value: ValueType

  init(value: ValueType) {
    self.value = value
  }
}

class Sample {
  var<DefaultBehavior> content: Int?
}

Here, "var" would create a container whose behavior is determined by a generic parameter; access of "content" would be mapped to that container.
I know behaviors are supposed to work slightly different, but that doesn't destroy the mental model of a parameterized container.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I’m sorry if this has already been discussed, but what are the drawbacks of putting the variable's behaviors before the ‘var’ keyword? Like this:

lazy synchronized var x:SomeType

With no prefix at all, this limits our ability to introduce declaration modifiers in the future. For instance, if the people clamoring for a `local` access modifier win in Swift 4, anyone who wrote a behavior called `local` will be very sad.

The other problem is, with this declaration:

  lazy var array = [1, 2, 3]

It offers no way to disambiguate between the two meanings of `lazy`:

  array.lazy.reset()
  array.lazy.map { ... }

Personally, if we're not going to use the `` syntax, I think we should use the `@` prefix and think of all uses of `@` throughout the language as eventual targets for behavior-ization (even if we don't get around to most of them in Swift 3, or some of them ever). It would be nice to have a rational explanation for what `@` means. But I'm reasonably happy with the `` syntax.

···

--
Brent Royal-Gordon
Architechies

Thanks for explaining. I forgot about access modifiers.

···

On Feb 14, 2016, at 12:36, Brent Royal-Gordon <brent@architechies.com> wrote:

I’m sorry if this has already been discussed, but what are the drawbacks of putting the variable's behaviors before the ‘var’ keyword? Like this:

lazy synchronized var x:SomeType

With no prefix at all, this limits our ability to introduce declaration modifiers in the future. For instance, if the people clamoring for a `local` access modifier win in Swift 4, anyone who wrote a behavior called `local` will be very sad.

The other problem is, with this declaration:

  lazy var array = [1, 2, 3]

It offers no way to disambiguate between the two meanings of `lazy`:

  array.lazy.reset()
  array.lazy.map { ... }

Personally, if we're not going to use the `` syntax, I think we should use the `@` prefix and think of all uses of `@` throughout the language as eventual targets for behavior-ization (even if we don't get around to most of them in Swift 3, or some of them ever). It would be nice to have a rational explanation for what `@` means. But I'm reasonably happy with the `` syntax.

Yes, the ‘@‘ seems worth thinking about here.

Matt

Hello,

It’s my first time using this mailing list, so please do let me know if I’m doing something wrong.

I personally agree with the `` syntax because it allows for something more like `[lazy, atomic]` without having to look a lot like Java annotations (which do something completely different). I think the `@` syntax should be reserved for compiler directives. The `` mechanism also could be expanded on like so:

/// abc is both lazy and atomic in behavior
var [lazy, atomic] abc: Int = 1234

/// ^ expands to:
var `abc.lazy` = LazyBehavior<Int> { 1234 }
var `abc.atomic`: AtomicBehavior<Int> { `abc.lazy` }
var abc: Int {
	get { return `abc.atomic`.get() }
	set(val) { `abc.atomic`.set(val) }
}

That is, in the order of appearance of the behaviors within the brackets, their behaviors will become a composed chain. Now this also means that some behaviors can only be initial or terminal, which must be specified through other syntactical means. In addition:

/// abc has behavior `myBehavior` which requires a parameter
var [myBehavior(parameter: true)] abc: Int = 1234

Again, this also further increases complexity, and possibly the need for a separate `behavior` declaration, instead of piggybacking on `protocol` (it could possibly be similar to `operator` syntax?).

···

--
Aditya Vaidyam

Purdue University
College of Science ‘17
Neurobiology and Physiology, Computer Science, Pre-medicine

On Feb 14, 2016, at 3:36 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

I’m sorry if this has already been discussed, but what are the drawbacks of putting the variable's behaviors before the ‘var’ keyword? Like this:

lazy synchronized var x:SomeType

With no prefix at all, this limits our ability to introduce declaration modifiers in the future. For instance, if the people clamoring for a `local` access modifier win in Swift 4, anyone who wrote a behavior called `local` will be very sad.

The other problem is, with this declaration:

  lazy var array = [1, 2, 3]

It offers no way to disambiguate between the two meanings of `lazy`:

  array.lazy.reset()
  array.lazy.map { ... }

Personally, if we're not going to use the `` syntax, I think we should use the `@` prefix and think of all uses of `@` throughout the language as eventual targets for behavior-ization (even if we don't get around to most of them in Swift 3, or some of them ever). It would be nice to have a rational explanation for what `@` means. But I'm reasonably happy with the `` syntax.

--
Brent Royal-Gordon
Architechies

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

As for the proposal itself:

      • What is your evaluation of the proposal?

+1.

However, like Brent says: "this proposal is a good core for property
behaviors, but alone, I don't think it carries its own weight. It will need
at least a couple of the items in "Future Directions" section before it's
really worth having."

In the fact, i prefer the first version of the proposal, the first version
is more "must do", this one is "just nice".

And i'm not convincing of the syntax to, i prefer something like that:
Pipe ( | | ) operator instead ``, `{ }` or `< >`

var |lazy| a = ...
var |observable| b = ...

and this to access:

a*#*clear() // yes, without the dot.
b*#*addObserver()

" delimiters are heavily array/collection/subscript-centric" (Chris)

      • Is the problem being addressed significant enough to warrant a

change to Swift?

Yes. Sure, i love the entire idea behind this proposal, i think this will
very beneficial for the language.

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

Yes.

      • If you have used other languages or libraries with a similar

feature, how do you feel that this proposal compares to those?

Just some "hacks" in Objective-C.

      • How much effort did you put into your review? A glance, a quick

reading, or an in-depth study?

I participated in the preliminary discussions re-read all variants of this
proposal a lot of times.

···

Em dom, 14 de fev de 2016 às 20:35, Haravikk via swift-evolution < swift-evolution@swift.org> escreveu:

> On 14 Feb 2016, at 11:08, Brent Royal-Gordon via swift-evolution < > swift-evolution@swift.org> wrote:
>
>> I ask again:
>> What is wrong with arrow brackets?
>>
>> var<lazy> foo
>
> var<lazy, synchronized> foo: Dictionary<Int, Set<Optional<String>>
>
> So, two problems:
>
> • Angle brackets already appear in var declarations for generic types;
that means there are two different meanings for angle brackets in the same
construct.
>
> • When we eventually allow you to apply multiple behaviors to a single
property, that will also mean that *commas* are used in both of those angle
bracket constructs, but with different meanings (one means "chain these",
the other means "fill these two slots").
>
> These are not fatal errors, but they're also completely unforced—either
`` or `{}` would not have this problem. So why choose the option that has
the problem?

Do we need braces and commas at all? It seems to me that you can just do:

        var lazy synchronized foo: Dictionary<Int, Set<Optional<String>>>

The name is always the one right before the colon, so this actually seems
fine to me. If Xcode can colour them differently then it shouldn’t be hard
to follow IMO. The order implies the order in which they are resolved where
relevant, i.e- foo is mutable, then lazy, then synchronised.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Linear composition is easy from an implementation point of view, so my concern is definitely in the "room-for-confusion" realm, especially since the potential for confusion is in the realm of things that are easy to miss in testing, such as race conditions.

-Joe

···

On Feb 15, 2016, at 3:09 PM, plx via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 15, 2016, at 4:45 PM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

On Feb 14, 2016, at 12:02 PM, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

As far as I have followed it, it does seem that it’s only `synchronized`-style behaviors that are fundamentally-problematic under composition; that is, using the terminology in the proposal, linear behavior composition would work fine, and to my eyes most behaviors are “linear”.

Behaviors that make synchronization promises are an obvious problem with composition, but there are also subtle issues with other compositions. Consider the composition of `lazy` with `didSet`—if you apply `didSet` inside `lazy`, you'll observe the lazy initialization as a "set" of the lazy storage, whereas you won't if you apply `lazy` inside `didSet`.

I see what you mean, but I’m curious:

Is there some fundamental implementation challenge here (e.g. `didSet` seeing an `oldValue` that might be initialized, unexpectedly-nil, or similar…)?

Or it this more of a “there’s too much room for confusion here”-style concern?