Re: [swift-evolution] [Proposal] Property behaviors

2015-12-25 Thread Howard Lovatt via swift-evolution
If a Property Behavior is 'officially' defined as a syntax sugar:

var _name = ...
var name: Type {
get { return _name }
set { _name = ... }
}

Then allow:

_name.behaviorMember ...

This is simple to implement, understand, and document. 

Sent from my iPad

> On 24 Dec 2015, at 5:30 PM, David Waite via swift-evolution 
>  wrote:
> 
> There was a proposal as well to get property accessor method access directly, 
> without referencing the function. 
> 
> If you had obj#myProperty.get() -> Val and obj#myProperty.set(_:Val) as 
> functions (# syntax being a placeholder more than a proposal) perhaps then 
> you could also have something like obj#myProperty.clear()
> 
> -DW
> 
>> On Dec 23, 2015, at 10:07 AM, Joe Groff via swift-evolution 
>>  wrote:
>> 
>> I agree that "myProperty.clear()" is very appealing, but it has the 
>> potential to be confusing when behavior methods are shadowed by members of 
>> the front-facing property. You'd still need a way to unambiguously refer to 
>> behavior methods when they're shadowed too.
>> 
>> -Joe
> 
> 
> ___
> 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


Re: [swift-evolution] [Proposal] Property behaviors

2015-12-23 Thread Joe Groff via swift-evolution

> On Dec 22, 2015, at 8:42 PM, Brent Royal-Gordon  
> wrote:
> 
>> You shouldn’t have to say myProperty.lazy.backingStore.clear(), just 
>> myProperty.lazy.clear().
>> 
>> I don’t know where that leaves us :-)
> 
> I wonder if these should all just be flattened into the instance that owns 
> the property. So instead of saying foo.myProperty.lazy.clear(), you just say 
> foo.clearMyProperty() or some such. That approach isn't very principled, but 
> it *is* very convenient.

I agree that "myProperty.clear()" is very appealing, but it has the potential 
to be confusing when behavior methods are shadowed by members of the 
front-facing property. You'd still need a way to unambiguously refer to 
behavior methods when they're shadowed too.

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


Re: [swift-evolution] [Proposal] Property behaviors

2015-12-23 Thread Tino Heth via swift-evolution
Quite complex proposal… guess I'll read it a second time when I'm less tired, 
but I have already one idea for the feature:
> Syntax for accessing the backing property
> 
When I saw the examples, I wondered right away "what if foo has an own property 
called runcible? How is the type modified to allow access to its backing 
property?" (that was my first interpretation on "foo.runcible")
I think all problems can be avoided without new keywords or a suffix with 
rarely used (or forbidden) character:
Just give the backing property for "foo" the name "super.foo".
- Afaik this is safe, because you can't create a property that already exists 
in the superclass (I guess it works if the property is not visible…)
- It's quite intuitive to me, because super always bypasses the normal behavior 
of self (well, commonly it refers to the superclass, but "bypass self" is just 
more general than superclass).

May the force be with you
Tino___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Proposal] Property behaviors

2015-12-23 Thread David Waite via swift-evolution
There was a proposal as well to get property accessor method access directly, 
without referencing the function. 

If you had obj#myProperty.get() -> Val and obj#myProperty.set(_:Val) as 
functions (# syntax being a placeholder more than a proposal) perhaps then you 
could also have something like obj#myProperty.clear()

-DW

> On Dec 23, 2015, at 10:07 AM, Joe Groff via swift-evolution 
>  wrote:
> 
> I agree that "myProperty.clear()" is very appealing, but it has the potential 
> to be confusing when behavior methods are shadowed by members of the 
> front-facing property. You'd still need a way to unambiguously refer to 
> behavior methods when they're shadowed too.
> 
> -Joe

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


Re: [swift-evolution] [Proposal] Property behaviors

2015-12-22 Thread Chris Lattner via swift-evolution
On Dec 22, 2015, at 9:08 AM, Joe Groff  wrote:
>>> 
>>> I think there’s value for users in being able to group and scope the 
>>> components associated with a particular behavior, so IMO it’s worth it.  
>>> Overall, it makes usage of the language less complex in practice.
>> 
>> I tend to agree.  There is definite value in having really independent 
>> things scoped out and cordoned off in their own areas.
> 
> On balance I like it too. Going with a behavior decl opens some questions 
> though:
> 
> - Can behaviors be extended?

>From an implementation perspective, I’d prefer not.  From a user model 
>perspective (which is what really matters :) we want to be able to add methods 
>to them somehow.  I think it would be fine to require more boilerplate for 
>this (e.g. the backing store for lazy is actually a struct, and that struct is 
>what gets the extension) - so long as it doesn’t cause boilerplate on the 
>client side.  You shouldn’t have to say myProperty.lazy.backingStore.clear(), 
>just myProperty.lazy.clear().

I don’t know where that leaves us :-)

> - Can behaviors be resilient? One nice thing about a fragile behavior is that 
> we can inline its storage, if any, directly into its containing type without 
> having to instantiate metadata for a nominal type, as we would for a 
> struct-based property implementation. A resilient behavior, however, would 
> end up needing more or less the same metadata to encapsulate the layout of 
> the behavior's state behind the resilience domain, weakening that benefit.

I’d be fine with requiring an explicit struct to be defined inline in the 
behavior to get resilience.

> - Should behaviors be able to control their default visibility policy? As 
> Brent and others pointed out, most behaviors are implementation details, but 
> the few that make sense as API generally always want to be API, such as 
> `resettable` or `KVOable`.

I’d suggest defining them to be private by default, and allowing the "var 
(public lazy)” sort of syntax.  After the basic proposal and model is done, we 
can then talk about adding a “public_by_default” trait to behavior to reduce 
boilerplate (if it is an issue in practice).

-Chris

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


Re: [swift-evolution] [Proposal] Property behaviors

2015-12-22 Thread Brent Royal-Gordon via swift-evolution
> You shouldn’t have to say myProperty.lazy.backingStore.clear(), just 
> myProperty.lazy.clear().
> 
> I don’t know where that leaves us :-)

I wonder if these should all just be flattened into the instance that owns the 
property. So instead of saying foo.myProperty.lazy.clear(), you just say 
foo.clearMyProperty() or some such. That approach isn't very principled, but it 
*is* very convenient.

-- 
Brent Royal-Gordon
Architechies

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


Re: [swift-evolution] [Proposal] Property behaviors

2015-12-21 Thread Joe Groff via swift-evolution

> On Dec 21, 2015, at 10:28 AM, Tal Atlas  wrote:
> 
> @Joe could you elaborate on the access pattern for these properties? Are you 
> getting back a boxed object every time or is there some sort of magic going 
> on so the caller thinks its getting the value inside the box but still has 
> some way to access methods on the box (say reset for the lazy property)

There's no boxing, the behavior effectively just inserts itself in the property 
chain. It would still act as if you had defined a backing property yourself:

var _backingProperty: Behavior
var property: T {
  get {
return _backingProperty.getBehavior()
  }
  set {
_backingProperty.setBehavior(newValue)
  }
}

It's true that, if the behavior is implemented in terms of get/set accessors, 
that this may introduce temporary copies while drilling down into the property. 
We have other accessor patterns we allow that can avoid this inefficiency that 
we would use in production implementations of things like `lazy` and `delayed`.

-Joe


> 
> On Mon, Dec 21, 2015 at 1:04 PM Matthew Johnson via swift-evolution 
> > wrote:
> I really like the direction this is heading Joe!  I agree it feels a lot 
> nicer.  It seems like the right long-term solution to me.
> 
> Making behaviors an explicit construct in the language may lead to 
> possibilities in the future that we cannot today which would not exist with 
> the ad-hoc approach. 
> 
>> On Dec 21, 2015, at 11:23 AM, Joe Groff via swift-evolution 
>> > wrote:
>> 
>> I played around a bit with the idea of a special behavior declaration. I 
>> think it feels a lot nicer, though it also feels like a much bigger language 
>> change if we go this route. Inside the declaration, you need to specify:
>> - what accessors the behavior supports, to be implemented by properties 
>> using the behavior,
>> - if the behavior controls storage, what that storage is, and what 
>> initialization logic it requires,
>> - if the behavior requires an initializer, and whether that initializer is 
>> used eagerly at property initialization or deferred to later, and
>> - what operations the behavior offers, if any.
>> 
>> Here's a quick sketch of how a behavior declaration could look. As a 
>> strawman, I'll use 'var behavior' as the introducer for a property behavior 
>> (leaving the door open to 'func behavior', 'struct behavior', etc. in the 
>> possible future). If you were going to reinvent computed properties from 
>> whole cloth, that might look like this:
>> 
>> var behavior computed {
>>   // A computed property requires a `get` and `set` accessor.
>>   accessor get() -> T
>>   accessor set(newValue: T)
>> 
>>   // Accessors for the property
>>   get { return get() }
>>   set { set(newValue) }
>> }
>> 
>> lazy might look something like this:
>> 
>> var behavior lazy {
>>   // lazy requires an initializer expression, but it isn't
>>   // used until after object initialization.
>>   deferred initializer: T
>> 
>>   // The optional storage for the property.
>>   var value: T?
>> 
>>   // Initialize the storage to nil.
>>   init() {
>> value = nil
>>   }
>> 
>>   // Accessors for the property.
>>   mutating get {
>> if let value = value {
>>   return value
>> }
>> // `initializer` is implicitly bound to the initializer expr as a
>> // `@noescape () -> T` within the behavior's members.
>> let initialValue = initializer()
>> value = initialValue
>> return initialValue
>>   }
>> 
>>   set {
>> value = newValue
>>   }
>> 
>>   // clear() operation for the behavior.
>>   mutating func clear() {
>> value = nil
>>   }
>> }
>> 
>> Some behaviors like `lazy` and `resettable` want to take control of the 
>> storage to manage their semantics, but many behaviors are adapters 
>> independent of how the underlying behavior behaves. These kinds of behavior 
>> are easy to compose with other behaviors and to override base class 
>> properties with. You could use inheritance-like syntax to indicate a 
>> "wrapping" behavior like this, and commandeer `super` to refer to the 
>> underlying property. For instance, `synchronized`:
>> 
>> var behavior synchronized: T {
>>   get {
>> return sync { return super }
>>   }
>>   set {
>> return sync { return super }
>>   }
>> }
>> 
>> or `observing` didSet/willSet:
>> 
>> var behavior observing: T {
>>   accessor willSet(oldValue: T, newValue: T) { }
>>   accessor didSet(oldValue: T, newValue: T) { }
>> 
>>   get { return super }
>>   set {
>> let oldValue = super
>> willSet(oldValue, newValue)
>> super = newValue
>> didSet(oldValue, newValue)
>>   }
>> }
>> 
>> If you want to refer back to the containing `self`, we could support that 
>> too, and by treating behavior functions specially we should be able to 
>> maintain coherent semantics for backreferencing value types as well. 
>> Implementing 

Re: [swift-evolution] [Proposal] Property behaviors

2015-12-21 Thread Matthew Johnson via swift-evolution
I really like the direction this is heading Joe!  I agree it feels a lot nicer. 
 It seems like the right long-term solution to me.

Making behaviors an explicit construct in the language may lead to 
possibilities in the future that we cannot today which would not exist with the 
ad-hoc approach. 

> On Dec 21, 2015, at 11:23 AM, Joe Groff via swift-evolution 
>  wrote:
> 
> I played around a bit with the idea of a special behavior declaration. I 
> think it feels a lot nicer, though it also feels like a much bigger language 
> change if we go this route. Inside the declaration, you need to specify:
> - what accessors the behavior supports, to be implemented by properties using 
> the behavior,
> - if the behavior controls storage, what that storage is, and what 
> initialization logic it requires,
> - if the behavior requires an initializer, and whether that initializer is 
> used eagerly at property initialization or deferred to later, and
> - what operations the behavior offers, if any.
> 
> Here's a quick sketch of how a behavior declaration could look. As a 
> strawman, I'll use 'var behavior' as the introducer for a property behavior 
> (leaving the door open to 'func behavior', 'struct behavior', etc. in the 
> possible future). If you were going to reinvent computed properties from 
> whole cloth, that might look like this:
> 
> var behavior computed {
>   // A computed property requires a `get` and `set` accessor.
>   accessor get() -> T
>   accessor set(newValue: T)
> 
>   // Accessors for the property
>   get { return get() }
>   set { set(newValue) }
> }
> 
> lazy might look something like this:
> 
> var behavior lazy {
>   // lazy requires an initializer expression, but it isn't
>   // used until after object initialization.
>   deferred initializer: T
> 
>   // The optional storage for the property.
>   var value: T?
> 
>   // Initialize the storage to nil.
>   init() {
> value = nil
>   }
> 
>   // Accessors for the property.
>   mutating get {
> if let value = value {
>   return value
> }
> // `initializer` is implicitly bound to the initializer expr as a
> // `@noescape () -> T` within the behavior's members.
> let initialValue = initializer()
> value = initialValue
> return initialValue
>   }
> 
>   set {
> value = newValue
>   }
> 
>   // clear() operation for the behavior.
>   mutating func clear() {
> value = nil
>   }
> }
> 
> Some behaviors like `lazy` and `resettable` want to take control of the 
> storage to manage their semantics, but many behaviors are adapters 
> independent of how the underlying behavior behaves. These kinds of behavior 
> are easy to compose with other behaviors and to override base class 
> properties with. You could use inheritance-like syntax to indicate a 
> "wrapping" behavior like this, and commandeer `super` to refer to the 
> underlying property. For instance, `synchronized`:
> 
> var behavior synchronized: T {
>   get {
> return sync { return super }
>   }
>   set {
> return sync { return super }
>   }
> }
> 
> or `observing` didSet/willSet:
> 
> var behavior observing: T {
>   accessor willSet(oldValue: T, newValue: T) { }
>   accessor didSet(oldValue: T, newValue: T) { }
> 
>   get { return super }
>   set {
> let oldValue = super
> willSet(oldValue, newValue)
> super = newValue
> didSet(oldValue, newValue)
>   }
> }
> 
> If you want to refer back to the containing `self`, we could support that 
> too, and by treating behavior functions specially we should be able to 
> maintain coherent semantics for backreferencing value types as well. 
> Implementing `synchronized` with a per-object lock could look like this:
> 
> var behavior synchronizedByObject: T where Self: Synchronizable {
>   get {
> return self.withLock { return super }
>   }
>   set {
> return self.withLock { return super }
>   }
> }
> 
> (though the juxtaposed meanings of `super` and `self` here are weird 
> together…we'd probably want a better implicit binding name for the underlying 
> property.)
> 
> -Joe
> 
> ___
> 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


Re: [swift-evolution] [Proposal] Property behaviors

2015-12-21 Thread Matthew Johnson via swift-evolution
I have been thinking further about the compiler diagnostics for `delayed`.  It 
might be interesting to consider making various compiler diagnostics available 
to any behavior rather than having a special case in the compiler for 
`delayed`.  

Here are some examples:

* By default properties with a behavior must be initialized in phase one just 
like normal properties.
* Behaviors can opt-in to a relaxed requirement that the property must be 
initialized *somewhere* in the initializer, but not necessarily phase one.  
Delayed would opt-in to this.
* Behaviors can opt-in to a requirement that the property *cannot* be set 
outside of an initializer.  Delayed would opt-in to this.
* Behaviors can opt-in to a requirement that the property *cannot* be set 
anywhere.  A variation of lazy might opt-in to this.  (clear would still work 
as it is part of the implementation of lazy)

Allowing behaviors to specify diagnostic behavior like this would probably be 
*possible* in the ad-hoc proposal.  However, it would probably be a lot more 
clear and elegant if we adopt the “behavior declaration” idea.

Matthew


> On Dec 21, 2015, at 11:23 AM, Joe Groff via swift-evolution 
>  wrote:
> 
> I played around a bit with the idea of a special behavior declaration. I 
> think it feels a lot nicer, though it also feels like a much bigger language 
> change if we go this route. Inside the declaration, you need to specify:
> - what accessors the behavior supports, to be implemented by properties using 
> the behavior,
> - if the behavior controls storage, what that storage is, and what 
> initialization logic it requires,
> - if the behavior requires an initializer, and whether that initializer is 
> used eagerly at property initialization or deferred to later, and
> - what operations the behavior offers, if any.
> 
> Here's a quick sketch of how a behavior declaration could look. As a 
> strawman, I'll use 'var behavior' as the introducer for a property behavior 
> (leaving the door open to 'func behavior', 'struct behavior', etc. in the 
> possible future). If you were going to reinvent computed properties from 
> whole cloth, that might look like this:
> 
> var behavior computed {
>   // A computed property requires a `get` and `set` accessor.
>   accessor get() -> T
>   accessor set(newValue: T)
> 
>   // Accessors for the property
>   get { return get() }
>   set { set(newValue) }
> }
> 
> lazy might look something like this:
> 
> var behavior lazy {
>   // lazy requires an initializer expression, but it isn't
>   // used until after object initialization.
>   deferred initializer: T
> 
>   // The optional storage for the property.
>   var value: T?
> 
>   // Initialize the storage to nil.
>   init() {
> value = nil
>   }
> 
>   // Accessors for the property.
>   mutating get {
> if let value = value {
>   return value
> }
> // `initializer` is implicitly bound to the initializer expr as a
> // `@noescape () -> T` within the behavior's members.
> let initialValue = initializer()
> value = initialValue
> return initialValue
>   }
> 
>   set {
> value = newValue
>   }
> 
>   // clear() operation for the behavior.
>   mutating func clear() {
> value = nil
>   }
> }
> 
> Some behaviors like `lazy` and `resettable` want to take control of the 
> storage to manage their semantics, but many behaviors are adapters 
> independent of how the underlying behavior behaves. These kinds of behavior 
> are easy to compose with other behaviors and to override base class 
> properties with. You could use inheritance-like syntax to indicate a 
> "wrapping" behavior like this, and commandeer `super` to refer to the 
> underlying property. For instance, `synchronized`:
> 
> var behavior synchronized: T {
>   get {
> return sync { return super }
>   }
>   set {
> return sync { return super }
>   }
> }
> 
> or `observing` didSet/willSet:
> 
> var behavior observing: T {
>   accessor willSet(oldValue: T, newValue: T) { }
>   accessor didSet(oldValue: T, newValue: T) { }
> 
>   get { return super }
>   set {
> let oldValue = super
> willSet(oldValue, newValue)
> super = newValue
> didSet(oldValue, newValue)
>   }
> }
> 
> If you want to refer back to the containing `self`, we could support that 
> too, and by treating behavior functions specially we should be able to 
> maintain coherent semantics for backreferencing value types as well. 
> Implementing `synchronized` with a per-object lock could look like this:
> 
> var behavior synchronizedByObject: T where Self: Synchronizable {
>   get {
> return self.withLock { return super }
>   }
>   set {
> return self.withLock { return super }
>   }
> }
> 
> (though the juxtaposed meanings of `super` and `self` here are weird 
> together…we'd probably want a better implicit binding name for the underlying 
> property.)
> 
> -Joe
> 
> ___
> swift-evolution 

Re: [swift-evolution] [Proposal] Property behaviors

2015-12-21 Thread Jordan Rose via swift-evolution
:-( I'm worried about increasing the size of the language this much. I really 
want to be able to say "behaviors are just syntactic sugar for declaring 
accessors and storage, and then everything else behaves normally". This makes 
them another entirely orthogonal decl kind, like operators.

Jordan

> On Dec 21, 2015, at 9:23 , Joe Groff via swift-evolution 
>  wrote:
> 
> I played around a bit with the idea of a special behavior declaration. I 
> think it feels a lot nicer, though it also feels like a much bigger language 
> change if we go this route. Inside the declaration, you need to specify:
> - what accessors the behavior supports, to be implemented by properties using 
> the behavior,
> - if the behavior controls storage, what that storage is, and what 
> initialization logic it requires,
> - if the behavior requires an initializer, and whether that initializer is 
> used eagerly at property initialization or deferred to later, and
> - what operations the behavior offers, if any.
> 
> Here's a quick sketch of how a behavior declaration could look. As a 
> strawman, I'll use 'var behavior' as the introducer for a property behavior 
> (leaving the door open to 'func behavior', 'struct behavior', etc. in the 
> possible future). If you were going to reinvent computed properties from 
> whole cloth, that might look like this:
> 
> var behavior computed {
>   // A computed property requires a `get` and `set` accessor.
>   accessor get() -> T
>   accessor set(newValue: T)
> 
>   // Accessors for the property
>   get { return get() }
>   set { set(newValue) }
> }
> 
> lazy might look something like this:
> 
> var behavior lazy {
>   // lazy requires an initializer expression, but it isn't
>   // used until after object initialization.
>   deferred initializer: T
> 
>   // The optional storage for the property.
>   var value: T?
> 
>   // Initialize the storage to nil.
>   init() {
> value = nil
>   }
> 
>   // Accessors for the property.
>   mutating get {
> if let value = value {
>   return value
> }
> // `initializer` is implicitly bound to the initializer expr as a
> // `@noescape () -> T` within the behavior's members.
> let initialValue = initializer()
> value = initialValue
> return initialValue
>   }
> 
>   set {
> value = newValue
>   }
> 
>   // clear() operation for the behavior.
>   mutating func clear() {
> value = nil
>   }
> }
> 
> Some behaviors like `lazy` and `resettable` want to take control of the 
> storage to manage their semantics, but many behaviors are adapters 
> independent of how the underlying behavior behaves. These kinds of behavior 
> are easy to compose with other behaviors and to override base class 
> properties with. You could use inheritance-like syntax to indicate a 
> "wrapping" behavior like this, and commandeer `super` to refer to the 
> underlying property. For instance, `synchronized`:
> 
> var behavior synchronized: T {
>   get {
> return sync { return super }
>   }
>   set {
> return sync { return super }
>   }
> }
> 
> or `observing` didSet/willSet:
> 
> var behavior observing: T {
>   accessor willSet(oldValue: T, newValue: T) { }
>   accessor didSet(oldValue: T, newValue: T) { }
> 
>   get { return super }
>   set {
> let oldValue = super
> willSet(oldValue, newValue)
> super = newValue
> didSet(oldValue, newValue)
>   }
> }
> 
> If you want to refer back to the containing `self`, we could support that 
> too, and by treating behavior functions specially we should be able to 
> maintain coherent semantics for backreferencing value types as well. 
> Implementing `synchronized` with a per-object lock could look like this:
> 
> var behavior synchronizedByObject: T where Self: Synchronizable {
>   get {
> return self.withLock { return super }
>   }
>   set {
> return self.withLock { return super }
>   }
> }
> 
> (though the juxtaposed meanings of `super` and `self` here are weird 
> together…we'd probably want a better implicit binding name for the underlying 
> property.)
> 
> -Joe
> 
> ___
> 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


Re: [swift-evolution] [Proposal] Property behaviors

2015-12-21 Thread Chris Lattner via swift-evolution

> On Dec 21, 2015, at 6:06 PM, Dave Abrahams via swift-evolution 
>  wrote:
> 
> 
>> On Dec 21, 2015, at 5:33 PM, Joe Groff via swift-evolution 
>>  wrote:
>> 
>> 
>>> On Dec 21, 2015, at 5:21 PM, Jordan Rose  wrote:
>>> 
>>> :-( I'm worried about increasing the size of the language this much. I 
>>> really want to be able to say "behaviors are just syntactic sugar for 
>>> declaring accessors and storage, and then everything else behaves 
>>> normally". This makes them another entirely orthogonal decl kind, like 
>>> operators.
>> 
>> I'd prefer not to have a new decl as well, if that was the best choice. 
>> However, it's still just syntactic sugar for declaring accessors and storage.
> 
> I think there’s value for users in being able to group and scope the 
> components associated with a particular behavior, so IMO it’s worth it.  
> Overall, it makes usage of the language less complex in practice.

I tend to agree.  There is definite value in having really independent things 
scoped out and cordoned off in their own areas.

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


Re: [swift-evolution] [Proposal] Property behaviors

2015-12-21 Thread Joe Groff via swift-evolution
I played around a bit with the idea of a special behavior declaration. I think 
it feels a lot nicer, though it also feels like a much bigger language change 
if we go this route. Inside the declaration, you need to specify:
- what accessors the behavior supports, to be implemented by properties using 
the behavior,
- if the behavior controls storage, what that storage is, and what 
initialization logic it requires,
- if the behavior requires an initializer, and whether that initializer is used 
eagerly at property initialization or deferred to later, and
- what operations the behavior offers, if any.

Here's a quick sketch of how a behavior declaration could look. As a strawman, 
I'll use 'var behavior' as the introducer for a property behavior (leaving the 
door open to 'func behavior', 'struct behavior', etc. in the possible future). 
If you were going to reinvent computed properties from whole cloth, that might 
look like this:

var behavior computed {
  // A computed property requires a `get` and `set` accessor.
  accessor get() -> T
  accessor set(newValue: T)

  // Accessors for the property
  get { return get() }
  set { set(newValue) }
}

lazy might look something like this:

var behavior lazy {
  // lazy requires an initializer expression, but it isn't
  // used until after object initialization.
  deferred initializer: T

  // The optional storage for the property.
  var value: T?

  // Initialize the storage to nil.
  init() {
value = nil
  }

  // Accessors for the property.
  mutating get {
if let value = value {
  return value
}
// `initializer` is implicitly bound to the initializer expr as a
// `@noescape () -> T` within the behavior's members.
let initialValue = initializer()
value = initialValue
return initialValue
  }

  set {
value = newValue
  }

  // clear() operation for the behavior.
  mutating func clear() {
value = nil
  }
}

Some behaviors like `lazy` and `resettable` want to take control of the storage 
to manage their semantics, but many behaviors are adapters independent of how 
the underlying behavior behaves. These kinds of behavior are easy to compose 
with other behaviors and to override base class properties with. You could use 
inheritance-like syntax to indicate a "wrapping" behavior like this, and 
commandeer `super` to refer to the underlying property. For instance, 
`synchronized`:

var behavior synchronized: T {
  get {
return sync { return super }
  }
  set {
return sync { return super }
  }
}

or `observing` didSet/willSet:

var behavior observing: T {
  accessor willSet(oldValue: T, newValue: T) { }
  accessor didSet(oldValue: T, newValue: T) { }

  get { return super }
  set {
let oldValue = super
willSet(oldValue, newValue)
super = newValue
didSet(oldValue, newValue)
  }
}

If you want to refer back to the containing `self`, we could support that too, 
and by treating behavior functions specially we should be able to maintain 
coherent semantics for backreferencing value types as well. Implementing 
`synchronized` with a per-object lock could look like this:

var behavior synchronizedByObject: T where Self: Synchronizable {
  get {
return self.withLock { return super }
  }
  set {
return self.withLock { return super }
  }
}

(though the juxtaposed meanings of `super` and `self` here are weird 
together…we'd probably want a better implicit binding name for the underlying 
property.)

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


Re: [swift-evolution] [Proposal] Property behaviors

2015-12-19 Thread Michel Fortin via swift-evolution
Le 18 déc. 2015 à 18:56, Kevin Ballard  a écrit :

> On Fri, Dec 18, 2015, at 07:18 AM, Michel Fortin wrote:
>> The reason I'm suggesting implementing synchronized as a behaviour instead 
>> of a type is because I found out with experience that synchronization should 
>> be related to variables, not types. Types exists in a vacuum while variables 
>> are bound to a context, and a synchronized access pattern should usually 
>> stay encapsulated in a particular context (struct or class). A 
>> Synchronized should not be copied or passed by reference and used out of 
>> its context; a property behaviour makes that just impossible, which is 
>> better.
> 
> I don't really understand what you're trying to say here. The goal you 
> describe (of not being able to copy or pass the synchronized value around) is 
> satisfied by having some way to declare a struct that cannot be copied (but 
> can be moved, because moves are always fine as long as there's no code (e.g. 
> other threads) that is still expecting the value to be at its original 
> location). Describing synchronized behavior as a non-copyable type like this 
> actually works extremely well in practice.

In essence, synchronization is an access policy for a variable. It's somewhat 
similar to `let` granting you only access to the getter, or the `Delayed` 
property behaviour that lets you use the setter only once.

Synchronization is an access policy stipulating that you should only use the 
getter and setter of the variable while the current thread has locked the 
associated mutex. While you could enforce that at runtime with fatalErrors in 
the setter and getter whenever the mutex is not locked (similar to `Delayed`), 
it's simply more convenient to enforce it at compile time by requiring a 
closure.

I acknowledge a type such as Synchronized will work fine for that too 
(assuming non-copyablility). I just think the modeling is slightly off. 
Synchronization is an access policy, not a data type, and it should be modeled 
in a similar manner to the other access policies in the language.

Language support for concurrency is out of scope for Swift 3, so it's perhaps 
premature to think about that now... but I can't help but think it'll have to 
work this way anyway the day Swift introduces a safe concurrency model.


-- 
Michel Fortin
michel.for...@michelf.ca
https://michelf.ca

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


Re: [swift-evolution] [Proposal] Property behaviors

2015-12-18 Thread plx via swift-evolution
I am excited by the general direction but I have some concerns about the scope 
of the design at this time; specifically, it seems like it would benefit a lot 
from having some flexible-and-efficient way for behaviors to “reach upward” 
back into their container from within their custom methods (without forcing the 
caller to pass-in the container to each such call, of course).

I took a stab at mocking up one of the behaviors I’d like to be able to write 
and hit a lot of roadblocks due to the above; I’ve included it below with some 
commentary. 

Even though this is perhaps a rather extreme/niche behavior to want to 
implement, I think the issues it encountered are actually general enough that 
other useful behaviors will also encounter them under the proposal as sketched.

Here’s the sample use, starting with motivation.

For some APIs — e.g. CoreBluetooth — you often wind up with highly-stateful 
objects that receive callbacks on a specific queue, and typically also do their 
state-maintenance while on that same queue; these objects typically also have a 
“public API” with methods that are only meant for use while off the queue (e.g. 
from the main queue, to update the UI…).

You thus wind up with each method-and-property pretty clearly being one and 
only one of these:

- “on-queue”, e.g. *only* meant for use while on the object’s queue
- “off-queue”, e.g. *only* meant for use while off the object’s queue

…with concurrency-and-synchronization logic essentially amounting to only 
calling / using each method-and-property while appropriately on/off queue.

For a concrete example, for an implementer of CBCentralManagerDelegate:

- all the CBCentralManagerDelegate methods are "on-queue"
- all the BT-state-management methods (called in reaction to BT events) are 
also “on-queue”
- the public methods (e.g. for UI use, or for asking the object to do stuff) 
are “off-queue”
- some of the basic properties (status, is-peripheral-foo-connected?) are 
oddballs, and get:
  - private backing properties for use/update while on-queue
  - public off-queue accessors that do a dispatch_sync, read the backing 
property, and return it

…and so on.

This can all be handled today "by hand” — it just requires being careful — but 
it’d be nice to have a custom behavior that would streamline both the 
implementation of on/off queue access for properties, and make each site-of-use 
more self-documenting/self-verifying vis-a-vis on/off-queue status.

Here’s my best attempt (issues flagged in ALL-CAPS):

/// Object assumed to have private queue it uses for synchronization.
protocol PrivateQueueOwner : class {

  // we don’t want to leak the actual queue to the wider world,
  // so we have to bubble these up to the public API:
  func dispatchSync(@noescape action: () -> R) -> R
  func dispatchBarrierSync(@noescape action: () -> R) -> R
  func dispatchAsync(action: () -> ())
  func dispatchBarrierAsync(action: () -> ())

  // we assume we are managing our queues s.t. we can
  // actually get the below to work reliably:
  func isOnPrivateQueue() -> Bool

}

/// Behavior used to enforce a particular use-pattern around
/// a property of an object that uses a private queue for synchronization:
struct QueueAccess {
  var value: Value
  
  // THIS PART IS ONLY-KINDA OK:
  subscript(varIn container: Container> {
get {
  if container.isOnPrivateQueue() {
return self.value
  } else {
return self.container.dispatchSync() {
  return self.value
  // ^ DOES THIS ACTUALLY WORK AS I’D WANT, IF I AM A STRUCT?
}
  }
}
set {
  if container.isOnPrivateQueue() { 
self.value = newValue
  } else {
container.dispatchBarrierAsync() {
  self.value = newValue
  // ^ DOES THIS ACTUALLY WORK AS I’D WANT, IF I AM A STRUCT?
}
  }
}
  }

  // EVERYTHING FROM HERE ON DOWN IS MOSTLY PROBLEMATIC:

  func onQueueUpdate(newValue: Value) { 
assert(self.container.isOnPrivateQueue()) // <- HOW?
self.value = newValue
  }
  
  func offQueueUpdate(newValue: Value) {
assert(self.container.isOffPrivateQueue()) // <- HOW?
self.container.dispatchBarrierAsync() { // <- HOW?
   self.value = newValue
   // ^ DOES THIS EVEN WORK IF I AM A STRUCT?   
}
  }

  func offQueueAccess() -> Value {
assert(self.container.isOffPrivateQueue()) // <- HOW?
return self.container.dispatchSync() { // <- HOW?
  return self.value
}
  }

  func onQueueAcccess() -> Value {
assert(self.container.isOnPrivateQueue()) // <- HOW?
return self.value
  }

  func offQueueAccess(@noescape transform: (Value) -> R) -> R {
assert(self.container.isOffPrivateQueue()) // <- HOW?
return self.container.dispatchSync() { // <- HOW?
  return transform(self.value)
}
  }

  func onQueueAcccess(@noescape transform: (Value) -> R) -> R {
assert(self.container.isOnPrivateQueue()) // <- HOW?
return transform(self.value)
  }

}


Re: [swift-evolution] [Proposal] Property behaviors

2015-12-18 Thread Chris Lattner via swift-evolution
On Dec 18, 2015, at 3:56 PM, Kevin Ballard via swift-evolution 
 wrote:
> Ultimately, I would love to have non-copyable structs in Swift. But the only 
> way to really do that is to have references in the language (otherwise the 
> moment you call a method on a non-copyable struct, you've lost the struct as 
> the value is moved into the method). And if you have references, you really 
> want them to be safe. Personally, I'd love to have the power of Rust's 
> borrowchecker and lifetimes system, but as I mentioned in another thread 
> recently, there is a pretty steep learning curve there.

Me too.  Two caveats:

- The model in swift should be opt-in: you should be able to use borrowing 
references in performance sensitive code, and get guarantees about (e.g.) no 
ARC.  You should be able to opt into making a struct move-only, and thus only 
work with those references, etc.  However, it shouldn’t be a required part of 
the programming model that all swift programmers need to confront to learn the 
language.

- This is certainly out of scope for swift 3 :-(OTOH, if someone were 
motivated to start exploring a concrete design in the space, it would be very 
very interesting.  One of the reasons that inout is where it is in the grammar 
is to allow other kinds of named parameter modifiers along the lines of Rust’s.

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


Re: [swift-evolution] [Proposal] Property behaviors

2015-12-18 Thread Stephen Christopher via swift-evolution
>
>
> When do properties with behaviors get included in the memberwise
>> initializer of structs or classes, if ever? Can properties with behaviors
>> be initialized from init rather than with inline initializers?
>>
>  There’s a separate discussion that mentioned allowing better control of
> which initializers are generated or synthesized for a given struct. There’s
> also been mention of a “derived” feature for adding conformance without
> needing to supply a separate implementation. This question seems related to
> me - it would be ideal if Swift had a coherent way to declare something
> that did not need definition because it can be generated by the compiler.
> In this case, to declare that a property is part of memberwise
> initialization. `behavior lazy: memberwise {` ?
>
>
> You might be talking about the initialization discussion I was involved in
> a week or so ago.  I'm working on a proposal that would allow for more
> flexible control over synthesized memberwise initialization.  I'm hoping to
> have a draft ready soon.
>

Great! Looking forward to reading it.


>
> Is your example here part of a behavior declaration for lazy which states
> that properties with the lazy behavior may be memberwise initialized?
> That's what it looks like to me.  I think syntax like that would make
> sense.  There are some behaviors which would need to opt out.  Somewhat
> ironically, I think lazy is one of them as the whole point of it is that it
> is not initialized immediately, but rather on first access.
>
> Yes, that was the idea behind that syntax. Hah, lazy was a terrible
example, you’re right. Distracted emailing never ends well.

It could be either opt-in (as my example hinted). Opt-out might be a bit
harder to express, and I’m not sure if opt-in is the right default.
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution