[swift-evolution] [Proposal] Property behaviors
Joe Groff
jgroff at apple.com
Mon Jan 18 22:03:18 CST 2016
> On Jan 18, 2016, at 7:57 PM, davesweeris at mac.com wrote:
>
> Can we use “#” or something other than “.”, both to make it clear we’re referencing a behavior rather than a property, and so that we can avoid naming collisions when x has a property “lazy” and is declared with the lazy behavior?
> x.lazy.clear() // a property named “lazy” which has a clear() method
> x#lazy.clear() // the behavior named “lazy”
> I kinda like “#” (or whatever) for declaring them, too:
> var x #(lazy) = 6
>
>
>
> I’m a definite +1 on the concepts behind your proposal, but there are really two distinct things going on here: behaviors that mess with the type, and those that don’t. I mean, if you define your Lazy “behavior” like this:
> struct Lazy<T> {
> private let closure: () -> T
> private var storage: T? = nil
> var value: T {
> mutating get {
> if storage == nil { storage = closure() }
> return storage!
> }
> mutating set {
> storage = newValue
> }
> }
> init(_ closure: () -> T) {
> self.closure = closure
> }
> }
>
> then the only difference between
> lazy var foo = {
> return 4
> }
> and
> var foo = Lazy {
> return 4
> }
> is that in the former case, the property is implicitly accessed:
> var bar = foo
> foo = 10
> and in the latter, we have to access it explicitly:
> var bar = foo.value
> foo.value = 10
>
> If we expose the mechanism currently used by `T!` to convert between itself and T, and allow structs, enums, classes, and maybe even protocols to provide type accessors as well as property accessors, Lazy, Optional, and ImplicitlyUnwrappedOptional could then be implemented like this:
> struct Lazy<T> {
> // or whatever the magic syntax is
> mutating static get { () -> T in // $0 is an instance of Lazy<T>
> if $0.value == nil { $0.value = $0.closure() }
> return $0.value!
> }
> mutating static set { (newValue:T) in $0.value = newValue }
>
> private let closure: () -> T
> private var value: T? = nil
> init(_ closure: () -> T) {
> self.value = closure
> }
> }
> enum Optional<T> {
> // no need for a custom getter, since you have to manually unwrap optionals
> mutating static set { (newValue: T) in $0 = .Some(newValue) } // $0 is an instance of Optional<T>
> mutating static set { () in $0 = .None }
>
> case None
> case Some(T)
> init() { self = .None }
> init(nilLiteral: ()) { self = .None }
> init(_ value: T) { self = .Some(value) }
> }
> enum ImplicitlyUnwrappedOptional<T> {
> mutating static get { () -> T in // $0 is an instance of ImplicitlyUnwrappedOptional<T>
> switch $0 {
> case .None: fatalError("Error unwrapping ImplicitlyUnwrappedOptional")
> case .Some(let value): return value
> }
> }
> mutating static set { (newValue: T) in $0 = .Some(newValue) }
> mutating static set { () in $0 = .None }
>
> case None
> case Some(T)
> init() { self = .None }
> init(nilLiteral: ()) { self = .None }
> init(_ value: T) { self = .Some(value) }
> }
>
> One of the stated goals of Swift 3 is to move stuff out of the core language and into the standard library, right? Well, this would get rid of all the “magic” behind Lazy, Optionals, and ImplicitlyUnwrappedOptionals and it’d let us implement our own type-related custom behaviors. It’s a win-win!
Getting rid of magic is definitely a goal, but I think we want to go in the *opposite* direction. Implicit Optional promotion creates lots of problems, and ImplicitlyUnwrappedOptional's behavior can be hard to predict. We plan to reform the type system around both kinds of Optional soon. Behaviors also give us an opportunity to eliminate at least one case for IUO by modeling delayed initialization as a behavior. I'd prefer not to introduce more messy implicit promotions.
-Joe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160118/eae834a7/attachment.html>
More information about the swift-evolution
mailing list