Skip to content

Property behaviors prototype#1297

Closed
jckarter wants to merge 5 commits intoswiftlang:masterfrom
jckarter:property-behaviors
Closed

Property behaviors prototype#1297
jckarter wants to merge 5 commits intoswiftlang:masterfrom
jckarter:property-behaviors

Conversation

@jckarter
Copy link
Contributor

Parse 'var [behavior] x: T', and when we see it, try to instantiate the property's
implementation in terms of the given behavior. To start out, behaviors are modeled
as protocols. If the protocol follows this pattern:

  protocol behavior {
    associatedtype Value
  }
  extension behavior {
    var value: Value { ... }
  }

then the property is instantiated by forming a conformance to behavior where
Self is bound to the enclosing type and Value is bound to the property's
declared type, and invoking the accessors of the value implementation:

  struct Foo {
    var [behavior] foo: Int
  }

  /* behaves like */

  extension Foo: private behavior {
    @implements(behavior.Value)
    private typealias `[behavior].Value` = Int

    var foo: Int {
      get { return value }
      set { value = newValue }
    }
  }

If the protocol requires a storage member, and provides an initStorage method
to provide an initial value to the storage:

  protocol storageBehavior {
    associatedtype Value

    var storage: Something<Value> { ... }
  }
  extension storageBehavior {
    var value: Value { ... }

    static func initStorage() -> Something<Value> { ... }
  }

then a stored property of the appropriate type is instantiated to witness the
requirement, using initStorage to initialize:

  struct Foo {
    var [storageBehavior] foo: Int
  }

  /* behaves like */

  extension Foo: private storageBehavior {
    @implements(storageBehavior.Value)
    private typealias `[storageBehavior].Value` = Int
    @implements(storageBehavior.storage)
    private var `[storageBehavior].storage`: Something<Int> = initStorage()

    var foo: Int {
      get { return value }
      set { value = newValue }
    }
  }

In either case, the value and storage properties should support any combination
of get-only/settable and mutating/nonmutating modifiers. The instantiated property
follows the settability and mutating-ness of the value implementation. The
protocol can also impose requirements on the Self and Value types.

Bells and whistles such as initializer expressions, accessors,
out-of-line initialization, etc. are not implemented. Additionally, behaviors
that instantiate storage are currently only supported on instance properties.
This also hasn't been tested past sema yet; SIL and IRGen will likely expose
additional issues.

@jckarter
Copy link
Contributor Author

@swift-ci Please test

@jckarter
Copy link
Contributor Author

@swift-ci Please test

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pointless edit here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing an 80-column violation.

@slavapestov
Copy link
Contributor

@jckarter This looks awesome. I just have a few nitpicks that you're free to ignore.

@jckarter
Copy link
Contributor Author

@swift-ci Please test

@jckarter
Copy link
Contributor Author

@swift-ci Please test

Parse 'var [behavior] x: T', and when we see it, try to instantiate the property's
implementation in terms of the given behavior. To start out, behaviors are modeled
as protocols. If the protocol follows this pattern:

  ```
  protocol behavior {
    associatedtype Value
  }
  extension behavior {
    var value: Value { ... }
  }
  ```

then the property is instantiated by forming a conformance to `behavior` where
`Self` is bound to the enclosing type and `Value` is bound to the property's
declared type, and invoking the accessors of the `value` implementation:

  ```
  struct Foo {
    var [behavior] foo: Int
  }

  /* behaves like */

  extension Foo: private behavior {
    @implements(behavior.Value)
    private typealias `[behavior].Value` = Int

    var foo: Int {
      get { return value }
      set { value = newValue }
    }
  }
  ```

If the protocol requires a `storage` member, and provides an `initStorage` method
to provide an initial value to the storage:

  ```
  protocol storageBehavior {
    associatedtype Value

    var storage: Something<Value> { ... }
  }
  extension storageBehavior {
    var value: Value { ... }

    static func initStorage() -> Something<Value> { ... }
  }
  ```

then a stored property of the appropriate type is instantiated to witness the
requirement, using `initStorage` to initialize:

  ```
  struct Foo {
    var [storageBehavior] foo: Int
  }

  /* behaves like */

  extension Foo: private storageBehavior {
    @implements(storageBehavior.Value)
    private typealias `[storageBehavior].Value` = Int
    @implements(storageBehavior.storage)
    private var `[storageBehavior].storage`: Something<Int> = initStorage()

    var foo: Int {
      get { return value }
      set { value = newValue }
    }
  }
  ```

In either case, the `value` and `storage` properties should support any combination
of get-only/settable and mutating/nonmutating modifiers. The instantiated property
follows the settability and mutating-ness of the `value` implementation. The
protocol can also impose requirements on the `Self` and `Value` types.

Bells and whistles such as initializer expressions, accessors,
out-of-line initialization, etc. are not implemented. Additionally, behaviors
that instantiate storage are currently only supported on instance properties.
This also hasn't been tested past sema yet; SIL and IRGen will likely expose
additional issues.
Fix some interface type/context type confusion in the AST synthesis from the previous patch, add a unique private mangling for behavior protocol conformances, and set up SILGen to emit the conformances when property declarations with behaviors are visited. Disable synthesis of the struct memberwise initializer if any instance properties use behaviors; codegen will need to be redesigned here.
We have enough implementation to do "delayed" now.
@jckarter jckarter changed the title Sema: Initial parsing and synthesis for properties with behaviors. Property behaviors prototype Feb 19, 2016
@jckarter
Copy link
Contributor Author

@swift-ci Please test

…rement.

Would be nice to have `guard` in C++...
Since the feature is incomplete and yet to be accepted or implemented as proposed, hide it behind an -enable-experimental-property-behaviors frontend flag.
@jckarter
Copy link
Contributor Author

@swift-ci Please test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants