[Proposal] Allow scoped properties from within computed properties


(Joseph Newton) #1

Hi,

I've done a lot of Objective-C and have been been a fan of Swift since it's
come out, however, there's a small feature of Objective-C that I would
really like to see implemented in Swift:

In Objective-C you have a few options implementation-wise when creating
properties for your class. You could use the *@synthesize *statement to
have the compiler create the backing ivar along with the appropriate
accessor methods or your could use the *@dynamic* statement to tell the
compiler that you're going to create your own accessor methods and backing
ivar (if needed).

Additionally, one could use the *@synthesize* statement to have the
compiler create the backing ivar, and then they could create custom
accessor methods to supply custom functionality or validation. I use this
third case extensively in my Objecitve-C code but there's not a concise way
of doing this in Swift.

For example, I might have an Objective-C implementation that looks like
this:

@interface Foo : NSObject
@property (nullable, copy) NSString *bar;
@end

@implementation Foo
@synthesize bar = _bar; // Creates ivar '_bar'

- (void)setBar:(NSString *)bar {
    if (bar.length < 100)
        _bar = nil;
    else
        _bar = [bar copy];
}

@end

Currently, the only way to implement this in Swift - AFAIK - is as follows:

class Foo {
    private var _bar: String?
    public var bar: String? {
        get { return _bar }
        set {
            if (newValue?.characters.count ?? 0) < 100 {
                _bar = nil
            }
            else {
                _bar = newValue.copy() as! String
            }
        }
    }
}

Although this works, it isn't exactly glamorous. The main drawback of this
implementation (unless intended) is that you now have any additional '_bar'
variable accessible within the scope of your class.

My proposal is to allow stored properties in the declaration block of
computed properties. For this example, the '_bar' declaration would simply
be moved inside of the declaration block for 'bar':

class Foo {
    public var bar: String? {
        var _bar: String?

        get { return _bar }
        set {
            if (newValue?.characters.count ?? 0) < 100 {
                _bar = nil
            }
            else {
                _bar = newValue.copy() as! String
            }
        }
    }
}

Only the getter and setter methods of 'bar' are allowed to access and
modify the stored '_bar' property. My proposal would also allow for
multiple stored properties of varying types within the scope of a single
computed property. This would also simply atomic synchronization for single
variables:

class Foo {
    static var synchronizedBar: String? {
        var queue = DispatchQueue(label: "Foo.synchronizedBar")
        var bar: String?

        get { return queue.sync { return bar } }
        set { queue.sync { bar = newValue } }
    }
}

Are there any suggestions or arguments, for or against, for this proposal?

-- Joe Newton


(David Sweeris) #2

Hi,

I've done a lot of Objective-C and have been been a fan of Swift since it's come out, however, there's a small feature of Objective-C that I would really like to see implemented in Swift:

In Objective-C you have a few options implementation-wise when creating properties for your class. You could use the @synthesize statement to have the compiler create the backing ivar along with the appropriate accessor methods or your could use the @dynamic statement to tell the compiler that you're going to create your own accessor methods and backing ivar (if needed).

Additionally, one could use the @synthesize statement to have the compiler create the backing ivar, and then they could create custom accessor methods to supply custom functionality or validation. I use this third case extensively in my Objecitve-C code but there's not a concise way of doing this in Swift.

For example, I might have an Objective-C implementation that looks like this:

@interface Foo : NSObject
@property (nullable, copy) NSString *bar;
@end

@implementation Foo
@synthesize bar = _bar; // Creates ivar '_bar'

- (void)setBar:(NSString *)bar {
    if (bar.length < 100)
        _bar = nil;
    else
        _bar = [bar copy];
}

@end

Currently, the only way to implement this in Swift - AFAIK - is as follows:

class Foo {
    private var _bar: String?
    public var bar: String? {
        get { return _bar }
        set {
            if (newValue?.characters.count ?? 0) < 100 {
                _bar = nil
            }
            else {
                _bar = newValue.copy() as! String
            }
        }
    }
}

Although this works, it isn't exactly glamorous. The main drawback of this implementation (unless intended) is that you now have any additional '_bar' variable accessible within the scope of your class.

I believe you can do this using didSet without the `_bar`:
class Foo {
    public var bar: String? {
        didSet {
            if (bar?.characters.count ?? 0) < 100 {
                bar = nil
            }
        }
    }
}

My proposal is to allow stored properties in the declaration block of computed properties. For this example, the '_bar' declaration would simply be moved inside of the declaration block for 'bar':

class Foo {
    public var bar: String? {
        var _bar: String?

        get { return _bar }
        set {
            if (newValue?.characters.count ?? 0) < 100 {
                _bar = nil
            }
            else {
                _bar = newValue.copy() as! String
            }
        }
    }
}

Only the getter and setter methods of 'bar' are allowed to access and modify the stored '_bar' property. My proposal would also allow for multiple stored properties of varying types within the scope of a single computed property. This would also simply atomic synchronization for single variables:

class Foo {
    static var synchronizedBar: String? {
        var queue = DispatchQueue(label: "Foo.synchronizedBar")
        var bar: String?

        get { return queue.sync { return bar } }
        set { queue.sync { bar = newValue } }
    }
}

Are there any suggestions or arguments, for or against, for this proposal?

It's an interesting idea, for sure. Because of the persistent storage required for `_bar`, I think one way to look at what you're proposing is essentially as a way to allow for a variable to be declared publicly as one type, be implemented as another (anonymous, in this case) type under the hood, and to specify a mechanism for automatically converting between the two types.

- Dave Sweeris

···

On Jan 13, 2017, at 11:27, Joseph Newton via swift-evolution <swift-evolution@swift.org> wrote:


(Xiaodi Wu) #3

There was a proposal for custom behaviors using `@`, which if I recall
would offer encapsulation along the lines of what you're proposing. It was
an extensively designed system which was deferred for consideration, but
which would be in scope again in phase 2. The proposal is in the
swift-evolution repository--does that address your use case?

···

On Fri, Jan 13, 2017 at 11:27 Joseph Newton via swift-evolution < swift-evolution@swift.org> wrote:

Hi,

I've done a lot of Objective-C and have been been a fan of Swift since
it's come out, however, there's a small feature of Objective-C that I would
really like to see implemented in Swift:

In Objective-C you have a few options implementation-wise when creating
properties for your class. You could use the *@synthesize *statement to
have the compiler create the backing ivar along with the appropriate
accessor methods or your could use the *@dynamic* statement to tell the
compiler that you're going to create your own accessor methods and backing
ivar (if needed).

Additionally, one could use the *@synthesize* statement to have the
compiler create the backing ivar, and then they could create custom
accessor methods to supply custom functionality or validation. I use this
third case extensively in my Objecitve-C code but there's not a concise way
of doing this in Swift.

For example, I might have an Objective-C implementation that looks like
this:

@interface Foo : NSObject
@property (nullable, copy) NSString *bar;
@end

@implementation Foo
@synthesize bar = _bar; // Creates ivar '_bar'

- (void)setBar:(NSString *)bar {
    if (bar.length < 100)
        _bar = nil;
    else
        _bar = [bar copy];
}

@end

Currently, the only way to implement this in Swift - AFAIK - is as follows:

class Foo {
    private var _bar: String?
    public var bar: String? {
        get { return _bar }
        set {
            if (newValue?.characters.count ?? 0) < 100 {
                _bar = nil
            }
            else {
                _bar = newValue.copy() as! String
            }
        }
    }
}

Although this works, it isn't exactly glamorous. The main drawback of this
implementation (unless intended) is that you now have any additional '_bar'
variable accessible within the scope of your class.

My proposal is to allow stored properties in the declaration block of
computed properties. For this example, the '_bar' declaration would simply
be moved inside of the declaration block for 'bar':

class Foo {
    public var bar: String? {
        var _bar: String?

        get { return _bar }
        set {
            if (newValue?.characters.count ?? 0) < 100 {
                _bar = nil
            }
            else {
                _bar = newValue.copy() as! String
            }
        }
    }
}

Only the getter and setter methods of 'bar' are allowed to access and
modify the stored '_bar' property. My proposal would also allow for
multiple stored properties of varying types within the scope of a single
computed property. This would also simply atomic synchronization for single
variables:

class Foo {
    static var synchronizedBar: String? {
        var queue = DispatchQueue(label: "Foo.synchronizedBar")
        var bar: String?

        get { return queue.sync { return bar } }
        set { queue.sync { bar = newValue } }
    }
}

Are there any suggestions or arguments, for or against, for this proposal?

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


(Joseph Newton) #4

Thank you for your responses Xiaodi and David,

I believe you can do this using didSet without the `_bar`:

class Foo {
    public var bar: String? {

        didSet {

            if (bar?.characters.count ?? 0) < 100 {
                bar = nil
            }
        }
    }
}

Yes, although this is a perfectly valid way of implementing this, I'm not a
big fan of implementing this functionality in this way. Particularly, I
don't like the concept of validating data after setting it, and then
re-setting the property if the validation failed. I would much rather
implement it in a manner where it's conditionally set depending on
validation.

It's an interesting idea, for sure. Because of the persistent storage

required for `_bar`, I *think* one way to look at what you're proposing
is essentially as a way to allow for a variable to be declared publicly
as one type, be implemented as another (anonymous, in this case) type under
the hood, and to specify a mechanism for automatically converting between
the two types.

Essentially, yes. The programmer would have the option of using these
nested properties to be able to add custom storage or functionality to any
computed property that they please.

(That said, there is a recurrent theme on this list where people ask for

new support for encapsulating members from visibility in ever smaller
scopes. I continue to be not in favor of the new `private`, but even
allowing its existence, providing all the permutations of
type/file/extension visibility is (afaict) and should continue to be (imo)
a non-goal. The distinction between public and internal not only avoids
pollution in your autocomplete list but also provides important safety
wins, and I think those gains are increasingly limited the finer we dice
these access levels.)

I'm not sure that I quite understand what you mean by this. Would you mind
elaborating?

I get that your proposal allows you to write one fewer declaration in the

case of an ad-hoc behavior than SE-0030 would. That is, in the case of
SE-0030, you'd have to declare both a behavior and a member that uses it;
in your case, you could declare just the member and implement the behavior
there. However, I think I'd want to see some concrete use cases that are
better served by this proposal than by SE-0030, which is the more general
solution as far as I can tell. In the two use cases you've mentioned, one
is served by `didSet`, and the other (`synchronized`) is a reusable
behavior for which SE-0030 offers the more elegant solution.

Here are some additional uses cases for this proposal:

*Implementing Objective-C's "__null_resettable"*

class Foo {
    var bar: UIColor! {
        var _bar: UIColor = .clear

        get { _return _bar }
        set { _bar = newValue ?? .clear }
    }
}

*Implementing a stack interface*

class Foo<T> {
    var currentItem: T? {
        var storage = [T]()

        get { return storage.last }
        set {
            if let newValue = newValue {
                storage.append(newValue)
            }
            else {
                storage.removeLast()
            }
        }
    }
}

*Validation before changing (for performance)*

class SessionManager {
    var session: Session {
        var _session: Session

        get { return _session }
        set {
            if newValue != _session {
            // expensive teardown code for the old session

            _session = newValue

            // expensive setup code for the new session
            }
        }
    }
}

Lastly, I've been doing some additional thinking and I think that it would
be beneficial to also setting values for these nested properties inside of
*init* methods. For example, I work with C APIs a great deal and create
Swift/ObjC wrappers for them a lot, I have a case where I provide an
implementation as follows:

class Wrapper {
    private var _unmanaged: UnsafePointer<UInt8>
    var text: String {
        return String(cString: _unmanaged)
    }

    fileprivate init(_ unmanaged: UnsafePointer<UInt8>) {
        _unamanged = unmanaged
    }
}

It's implemented in this manner because the C APIs may change the
characters pointed to by *_unmanaged* before the *text* property is
accessed. With this proposal, this code could be implemented as follows:

class Wrapper {
    var text: String {
        private var unmanaged: UnsafePointer<UInt8>

        get {
            return String(cString: unmanaged)
        }
    }

    fileprivate init(_ unmanaged: UnsafePointer<UInt8>) {
        self.text.unmanaged = unmanaged
    }
}

···

On Fri, Jan 13, 2017 at 4:01 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

(Forward to the list if your early replied was intended to be sent there.)

On Fri, Jan 13, 2017 at 1:58 PM, Joseph Newton <jnewto32@gmail.com> wrote:

I believe that you're referring to SE-0030 Property Behaviors
<https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md>,
correct?

I have indeed read over this proposal (I probably should have mentioned
that in my first message) but I don't believe that it quite covers what I'm
going for (or over-covers it).

The reason I mentioned it was because the use case sounded vaguely
familiar. Reading over SE-0030, you'll see that one specific example is
synchronized property access. It demonstrates how SE-0030 would enable a
behavior called `synchronized` that would allow you to write, for any
arbitrary member foo, `public [synchronized] var foo: String`. It would
make it more than just easy to implement such a behavior for any member:
you would not have to write anything but `[synchronized]`.

As to your other use case, the case of validating a set value, David
Sweeris has pointed out that `didSet` currently enables that functionality
pretty well.

SE-0030 proposes making property behaviors requiring a specific
declaration and implementation of a particular behavior just to be able to
add stored properties to computed properties. Additionally, if you look at
the "Properties and Methods in Behaviors" section of the proposal, you'll
see that any stored property declared inside of a behavior is given the
same access level as the property that is using the behavior. Although this
could be convenient in some circumstances, my proposal calls for these
stored properties to be private to the scope of the property declaration so
as to avoid namespace pollution.

I think you misunderstand that text, or maybe I do. It says that the
properties and methods are expanded into the containing scope, and that
they must be of _types_ that are visible at the call site. However, the
examples given for reimplementing lazy show very clearly that the
properties and methods can be declared private:

public var behavior lazy<Value>: Value {
  private var value: Value?
  // ...
}

SE-0030 was written before `fileprivate` and `private` were separated; if
it were implemented today, it would make sense that `private` would cause
`value` to be invisible outside the behavior. Even at the time, a `private`
underlying `value` shouldn't be (unless I'm mistaken) visible outside the
file.

(That said, there is a recurrent theme on this list where people ask for
new support for encapsulating members from visibility in ever smaller
scopes. I continue to be not in favor of the new `private`, but even
allowing its existence, providing all the permutations of
type/file/extension visibility is (afaict) and should continue to be (imo)
a non-goal. The distinction between public and internal not only avoids
pollution in your autocomplete list but also provides important safety
wins, and I think those gains are increasingly limited the finer we dice
these access levels.)

My proposal makes this feature (stored properties inside of computed

properties) significantly easier to implement. For singular or unique cases
of needing this functionality, in lieu of having to learn "Property
Behaviors," its syntax and how to effectively write them, one would only
need to add their properties to their computed properties' declaration
block.

Thoughts?

I get that your proposal allows you to write one fewer declaration in the
case of an ad-hoc behavior than SE-0030 would. That is, in the case of
SE-0030, you'd have to declare both a behavior and a member that uses it;
in your case, you could declare just the member and implement the behavior
there. However, I think I'd want to see some concrete use cases that are
better served by this proposal than by SE-0030, which is the more general
solution as far as I can tell. In the two use cases you've mentioned, one
is served by `didSet`, and the other (`synchronized`) is a reusable
behavior for which SE-0030 offers the more elegant solution.

On Fri, Jan 13, 2017 at 12:34 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

There was a proposal for custom behaviors using `@`, which if I recall
would offer encapsulation along the lines of what you're proposing. It was
an extensively designed system which was deferred for consideration, but
which would be in scope again in phase 2. The proposal is in the
swift-evolution repository--does that address your use case?
On Fri, Jan 13, 2017 at 11:27 Joseph Newton via swift-evolution < >>> swift-evolution@swift.org> wrote:

Hi,

I've done a lot of Objective-C and have been been a fan of Swift since
it's come out, however, there's a small feature of Objective-C that I would
really like to see implemented in Swift:

In Objective-C you have a few options implementation-wise when creating
properties for your class. You could use the *@synthesize *statement
to have the compiler create the backing ivar along with the appropriate
accessor methods or your could use the *@dynamic* statement to tell
the compiler that you're going to create your own accessor methods and
backing ivar (if needed).

Additionally, one could use the *@synthesize* statement to have the
compiler create the backing ivar, and then they could create custom
accessor methods to supply custom functionality or validation. I use this
third case extensively in my Objecitve-C code but there's not a concise way
of doing this in Swift.

For example, I might have an Objective-C implementation that looks like
this:

@interface Foo : NSObject
@property (nullable, copy) NSString *bar;
@end

@implementation Foo
@synthesize bar = _bar; // Creates ivar '_bar'

- (void)setBar:(NSString *)bar {
    if (bar.length < 100)
        _bar = nil;
    else
        _bar = [bar copy];
}

@end

Currently, the only way to implement this in Swift - AFAIK - is as
follows:

class Foo {
    private var _bar: String?
    public var bar: String? {
        get { return _bar }
        set {
            if (newValue?.characters.count ?? 0) < 100 {
                _bar = nil
            }
            else {
                _bar = newValue.copy() as! String
            }
        }
    }
}

Although this works, it isn't exactly glamorous. The main drawback of
this implementation (unless intended) is that you now have any additional
'_bar' variable accessible within the scope of your class.

My proposal is to allow stored properties in the declaration block of
computed properties. For this example, the '_bar' declaration would simply
be moved inside of the declaration block for 'bar':

class Foo {
    public var bar: String? {
        var _bar: String?

        get { return _bar }
        set {
            if (newValue?.characters.count ?? 0) < 100 {
                _bar = nil
            }
            else {
                _bar = newValue.copy() as! String
            }
        }
    }
}

Only the getter and setter methods of 'bar' are allowed to access and
modify the stored '_bar' property. My proposal would also allow for
multiple stored properties of varying types within the scope of a single
computed property. This would also simply atomic synchronization for single
variables:

class Foo {
    static var synchronizedBar: String? {
        var queue = DispatchQueue(label: "Foo.synchronizedBar")
        var bar: String?

        get { return queue.sync { return bar } }
        set { queue.sync { bar = newValue } }
    }
}

Are there any suggestions or arguments, for or against, for this
proposal?

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


(Xiaodi Wu) #5

Thank you for your responses Xiaodi and David,

I believe you can do this using didSet without the `_bar`:

class Foo {
    public var bar: String? {

        didSet {

            if (bar?.characters.count ?? 0) < 100 {
                bar = nil
            }
        }
    }
}

Yes, although this is a perfectly valid way of implementing this, I'm not
a big fan of implementing this functionality in this way. Particularly, I
don't like the concept of validating data after setting it, and then
re-setting the property if the validation failed. I would much rather
implement it in a manner where it's conditionally set depending on
validation.

It's an interesting idea, for sure. Because of the persistent storage

required for `_bar`, I *think* one way to look at what you're proposing
is essentially as a way to allow for a variable to be declared publicly
as one type, be implemented as another (anonymous, in this case) type under
the hood, and to specify a mechanism for automatically converting between
the two types.

Essentially, yes. The programmer would have the option of using these
nested properties to be able to add custom storage or functionality to any
computed property that they please.

(That said, there is a recurrent theme on this list where people ask for

new support for encapsulating members from visibility in ever smaller
scopes. I continue to be not in favor of the new `private`, but even
allowing its existence, providing all the permutations of
type/file/extension visibility is (afaict) and should continue to be (imo)
a non-goal. The distinction between public and internal not only avoids
pollution in your autocomplete list but also provides important safety
wins, and I think those gains are increasingly limited the finer we dice
these access levels.)

I'm not sure that I quite understand what you mean by this. Would you mind
elaborating?

See below.

I get that your proposal allows you to write one fewer declaration in

the case of an ad-hoc behavior than SE-0030 would. That is, in the case of
SE-0030, you'd have to declare both a behavior and a member that uses it;
in your case, you could declare just the member and implement the behavior
there. However, I think I'd want to see some concrete use cases that are
better served by this proposal than by SE-0030, which is the more general
solution as far as I can tell. In the two use cases you've mentioned, one
is served by `didSet`, and the other (`synchronized`) is a reusable
behavior for which SE-0030 offers the more elegant solution.

Here are some additional uses cases for this proposal:

*Implementing Objective-C's "__null_resettable"*

class Foo {
    var bar: UIColor! {
        var _bar: UIColor = .clear

        get { _return _bar }
        set { _bar = newValue ?? .clear }
    }
}

In this use case, your proposal differs from what's currently possible only
in that `_bar` (presumably, after you write `private` in front of it, for
consistency with current rules about default access levels) would be
invisible even inside `Foo`. As I wrote to you above, avoiding "pollution"
within ever smaller scopes [in this case, the scope inside `Foo`] is
(AFAICT) and should be (IMO) a non-goal. To convince me that this use case
is worth the engineering effort and complexity of a new syntax, you'd also
have to convince me that having `_bar` visible within the entire scope of
`Foo` has practical and not merely theoretical footgun potential or some
other negative impact beyond the fact that autocomplete will show a member
you'd rather not see.

_Even if_ I were to buy that argument, I think there is a more general
solution that covers your use case. A few months earlier on this list,
several people discussed the possibility of same-module extensions allowing
stored properties, to very positive reception. There are numerous use cases
for that feature, but such a feature would also allow you to isolate `_bar`
and `bar` in its own extension, a common Swift idiom. It would also allow
you to group this implementation in the same extension with arbitrary
functions that need to see `_bar` (such as your `init(_:)` example below)
without exposing `_bar` to other initializer and methods that don't need to
manipulate it. This would be both more flexible and more fine-grained than
possible with your own proposal, and if I were to buy your argument that
`_bar` being visible where it's not needed is suboptimal, this would be the
optimal solution.

*Implementing a stack interface*

class Foo<T> {
    var currentItem: T? {
        var storage = [T]()

        get { return storage.last }
        set {
            if let newValue = newValue {
                storage.append(newValue)
            }
            else {
                storage.removeLast()
            }
        }
    }
}

I'm not sure I understand why this requires your proposed feature, other
than again that it hides `storage` from the rest of `Foo<T>`.

*Validation before changing (for performance)*

class SessionManager {
    var session: Session {
        var _session: Session

        get { return _session }
        set {
            if newValue != _session {
            // expensive teardown code for the old session

            _session = newValue

            // expensive setup code for the new session
            }
        }
    }
}

This can be implemented using `willSet` and `didSet` (taking your example
at face value, where it's not the actual swapping of newValue and _session
that is expensive but rather the teardown and setup, assuming `==` and `!=`
are implemented correctly, i.e. in such a way that `newValue == _session`
implies that the two fully instantiated values really are interchangeable
in every way that matters).

Lastly, I've been doing some additional thinking and I think that it would

be beneficial to also setting values for these nested properties inside of
*init* methods. For example, I work with C APIs a great deal and create
Swift/ObjC wrappers for them a lot, I have a case where I provide an
implementation as follows:

class Wrapper {
    private var _unmanaged: UnsafePointer<UInt8>
    var text: String {
        return String(cString: _unmanaged)
    }

    fileprivate init(_ unmanaged: UnsafePointer<UInt8>) {
        _unamanged = unmanaged
    }
}

It's implemented in this manner because the C APIs may change the
characters pointed to by *_unmanaged* before the *text* property is
accessed. With this proposal, this code could be implemented as follows:

class Wrapper {
    var text: String {
        private var unmanaged: UnsafePointer<UInt8>

        get {
            return String(cString: unmanaged)
        }
    }

    fileprivate init(_ unmanaged: UnsafePointer<UInt8>) {
        self.text.unmanaged = unmanaged
    }
}

Unless I'm mistaken, this addendum to your idea can't be reconciled with
access control rules. A `private` var is hidden from _all_ methods not in
scope. One shouldn't (and probably can't, from an implementation
perspective) start making rules saying that certain `private` vars are
visible to initializers.

Using your proposed feature, you'd have to make `unmanaged` in this case
`fileprivate` and then implement the rest of `Wrapper` in an extension in a
different file if you want to hide `unmanaged` from those methods but leave
it visible to your initializer. By contrast, if you left `unmanaged` as a
private var directly inside `Wrapper`, you could hide `unmanaged` from any
methods implemented in an extension without having to move that extension
to a different file, probably a cleaner result if this kind of fine-grained
hiding from autocomplete is what you're after.

···

On Sat, Jan 14, 2017 at 9:36 AM, Joseph Newton <jnewto32@gmail.com> wrote:

On Fri, Jan 13, 2017 at 4:01 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

(Forward to the list if your early replied was intended to be sent there.)

On Fri, Jan 13, 2017 at 1:58 PM, Joseph Newton <jnewto32@gmail.com> >> wrote:

I believe that you're referring to SE-0030 Property Behaviors
<https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md>,
correct?

I have indeed read over this proposal (I probably should have mentioned
that in my first message) but I don't believe that it quite covers what I'm
going for (or over-covers it).

The reason I mentioned it was because the use case sounded vaguely
familiar. Reading over SE-0030, you'll see that one specific example is
synchronized property access. It demonstrates how SE-0030 would enable a
behavior called `synchronized` that would allow you to write, for any
arbitrary member foo, `public [synchronized] var foo: String`. It would
make it more than just easy to implement such a behavior for any member:
you would not have to write anything but `[synchronized]`.

As to your other use case, the case of validating a set value, David
Sweeris has pointed out that `didSet` currently enables that functionality
pretty well.

SE-0030 proposes making property behaviors requiring a specific
declaration and implementation of a particular behavior just to be able to
add stored properties to computed properties. Additionally, if you look at
the "Properties and Methods in Behaviors" section of the proposal, you'll
see that any stored property declared inside of a behavior is given the
same access level as the property that is using the behavior. Although this
could be convenient in some circumstances, my proposal calls for these
stored properties to be private to the scope of the property declaration so
as to avoid namespace pollution.

I think you misunderstand that text, or maybe I do. It says that the
properties and methods are expanded into the containing scope, and that
they must be of _types_ that are visible at the call site. However, the
examples given for reimplementing lazy show very clearly that the
properties and methods can be declared private:

public var behavior lazy<Value>: Value {
  private var value: Value?
  // ...
}

SE-0030 was written before `fileprivate` and `private` were separated; if
it were implemented today, it would make sense that `private` would cause
`value` to be invisible outside the behavior. Even at the time, a `private`
underlying `value` shouldn't be (unless I'm mistaken) visible outside the
file.

(That said, there is a recurrent theme on this list where people ask for
new support for encapsulating members from visibility in ever smaller
scopes. I continue to be not in favor of the new `private`, but even
allowing its existence, providing all the permutations of
type/file/extension visibility is (afaict) and should continue to be (imo)
a non-goal. The distinction between public and internal not only avoids
pollution in your autocomplete list but also provides important safety
wins, and I think those gains are increasingly limited the finer we dice
these access levels.)

My proposal makes this feature (stored properties inside of computed

properties) significantly easier to implement. For singular or unique cases
of needing this functionality, in lieu of having to learn "Property
Behaviors," its syntax and how to effectively write them, one would only
need to add their properties to their computed properties' declaration
block.

Thoughts?

I get that your proposal allows you to write one fewer declaration in the
case of an ad-hoc behavior than SE-0030 would. That is, in the case of
SE-0030, you'd have to declare both a behavior and a member that uses it;
in your case, you could declare just the member and implement the behavior
there. However, I think I'd want to see some concrete use cases that are
better served by this proposal than by SE-0030, which is the more general
solution as far as I can tell. In the two use cases you've mentioned, one
is served by `didSet`, and the other (`synchronized`) is a reusable
behavior for which SE-0030 offers the more elegant solution.

On Fri, Jan 13, 2017 at 12:34 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

There was a proposal for custom behaviors using `@`, which if I recall
would offer encapsulation along the lines of what you're proposing. It was
an extensively designed system which was deferred for consideration, but
which would be in scope again in phase 2. The proposal is in the
swift-evolution repository--does that address your use case?
On Fri, Jan 13, 2017 at 11:27 Joseph Newton via swift-evolution < >>>> swift-evolution@swift.org> wrote:

Hi,

I've done a lot of Objective-C and have been been a fan of Swift since
it's come out, however, there's a small feature of Objective-C that I would
really like to see implemented in Swift:

In Objective-C you have a few options implementation-wise when
creating properties for your class. You could use the *@synthesize *statement
to have the compiler create the backing ivar along with the appropriate
accessor methods or your could use the *@dynamic* statement to tell
the compiler that you're going to create your own accessor methods and
backing ivar (if needed).

Additionally, one could use the *@synthesize* statement to have the
compiler create the backing ivar, and then they could create custom
accessor methods to supply custom functionality or validation. I use this
third case extensively in my Objecitve-C code but there's not a concise way
of doing this in Swift.

For example, I might have an Objective-C implementation that looks
like this:

@interface Foo : NSObject
@property (nullable, copy) NSString *bar;
@end

@implementation Foo
@synthesize bar = _bar; // Creates ivar '_bar'

- (void)setBar:(NSString *)bar {
    if (bar.length < 100)
        _bar = nil;
    else
        _bar = [bar copy];
}

@end

Currently, the only way to implement this in Swift - AFAIK - is as
follows:

class Foo {
    private var _bar: String?
    public var bar: String? {
        get { return _bar }
        set {
            if (newValue?.characters.count ?? 0) < 100 {
                _bar = nil
            }
            else {
                _bar = newValue.copy() as! String
            }
        }
    }
}

Although this works, it isn't exactly glamorous. The main drawback of
this implementation (unless intended) is that you now have any additional
'_bar' variable accessible within the scope of your class.

My proposal is to allow stored properties in the declaration block of
computed properties. For this example, the '_bar' declaration would simply
be moved inside of the declaration block for 'bar':

class Foo {
    public var bar: String? {
        var _bar: String?

        get { return _bar }
        set {
            if (newValue?.characters.count ?? 0) < 100 {
                _bar = nil
            }
            else {
                _bar = newValue.copy() as! String
            }
        }
    }
}

Only the getter and setter methods of 'bar' are allowed to access and
modify the stored '_bar' property. My proposal would also allow for
multiple stored properties of varying types within the scope of a single
computed property. This would also simply atomic synchronization for single
variables:

class Foo {
    static var synchronizedBar: String? {
        var queue = DispatchQueue(label: "Foo.synchronizedBar")
        var bar: String?

        get { return queue.sync { return bar } }
        set { queue.sync { bar = newValue } }
    }
}

Are there any suggestions or arguments, for or against, for this
proposal?

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