Proposal: willGet


(Paul Cantrell) #1

I can see several potential problems with this proposal, but it’s straightforward in concept, so I’m throwing it out for everyone to pick apart.

MOTIVATION

Siesta has several API calls that, like UIView hierarchies for example, should only be used from the main thread. (Yes, there are good design reasons for this. I’ll spare you the details.)

I have an assertMainThread() sanity check designed to catch developer thread usage mistakes at development time. I’m running through my public methods, adding calls where appropriate.

However, what I _really_ want to guard is not methods but properties. I’d need to add assertMainThread() in far fewer places, and would achieve better coverage, if I could attach it to property access.

PROPOSAL

Provide a “willGet” decorator for properties.

It cannot affect the returned value, and thus does not make the property a computed property. That means it can be attached even to let properties:

    let foo: String {
        willGet { assertMainThread() }
    }

Possible uses:

  access preconditions
  logging
  access counting / profiling

ALTERNATIVES

Of course I can do this:

    var foo: String {
        get {
            assertMainThread()
            return _foo
        }
        set {
            assertMainThread()
           _foo = newValue
        }
    }

    private var _foo: String

…but that gets messy when multiplied over all properties. Much nicer to do this:

    var foo: String {
        willGet { assertMainThread() }
        willSet { assertMainThread() }
    }

QUESTIONS / CRITIQUES

I know there’s talk on the core team of some more robust property decoration mechanism. Does this already fold into that effort?

Should willGet allow side effects? If so, does the existence of mutating getters in structs play out nonsensically?

Does this complicate the computed / non-computed property distinction for the compiler?

Does this preclude useful optimizations?

Does this open the door to horrible, horrible code? Wait, I know the answer to that one. It is a programming language feature … so yes, yes it does.

Cheers,

Paul

–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
https://innig.net@inthehandshttp://siestaframework.com/


(Chris Lattner) #2

PROPOSAL

Provide a “willGet” decorator for properties.

It cannot affect the returned value, and thus does not make the property a computed property. That means it can be attached even to let properties:

   let foo: String {
       willGet { assertMainThread() }
   }

My opinion is that this is too narrow to be worth complicating the language for. Property observers are simply sugar for computed getters, and we only did them in Swift 1 because they use-cases they covered were so common. The hope is that we can eliminate them as a language concept and move them out to the standard library as well.

QUESTIONS / CRITIQUES

I know there’s talk on the core team of some more robust property decoration mechanism. Does this already fold into that effort?

Yes, I believe that this should be covered by that work, which is great. :-)

Should willGet allow side effects? If so, does the existence of mutating getters in structs play out nonsensically?

It depends on what you mean. Swift does support “mutating getters”, but that means the getter cannot be used on a “let” value of that type. If you mean side effects in general (e.g. calling print) then that would be fine (but probably still not a great idea for predictability :-)

Does this complicate the computed / non-computed property distinction for the compiler?

No, this is sugar for computed properties.

Does this preclude useful optimizations?

As stated, probably not.

Does this open the door to horrible, horrible code? Wait, I know the answer to that one. It is a programming language feature … so yes, yes it does.

exactly! :-)

-Chris

···

On Dec 13, 2015, at 11:23 AM, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:


(Paul Cantrell) #3

I know there’s talk on the core team of some more robust property decoration mechanism. Does this already fold into that effort?

Yes, I believe that this should be covered by that work, which is great. :slight_smile:

Then I’d plop it in as a use case (admittedly one of the less compelling ones) for that work, and drop this proposal.

Is any of that work public yet? It sounds exciting. (Apologies if that question is a repeat; I confess that I have not followed every single message on this list.)

Cheers, P


(Chris Lattner) #4

Not yet. Joe Groff is driving the proposal, but has a number of other things on his plate as well. Our goal is to get it out before our holiday break, which starts Dec 24, but it might slip into the new year depending on how other things go.

-Chris

···

On Dec 13, 2015, at 1:48 PM, Paul Cantrell <cantrell@pobox.com> wrote:

I know there’s talk on the core team of some more robust property decoration mechanism. Does this already fold into that effort?

Yes, I believe that this should be covered by that work, which is great. :-)

Then I’d plop it in as a use case (admittedly one of the less compelling ones) for that work, and drop this proposal.

Is any of that work public yet?


(Andrew Bennett) #5

Hi, this is an alternative to your proposal, taking into account Chris'
comments.

You could add precondition and postcondition on protocol methods and
properties, for example:

protocol Configurable {
    typealias Configuration

    var configured: Bool {
        @non-mutating get
        set { precondition { configured == false } }
    }

    // unsure if this syntax is confusing, but it's consistent with get/set
    func configure(configuration: Configuration) {
        precondition { configured == false }
        postcondition { configured == true }
    }
}

The terms precondition, postcondition and @non-mutating are up for debate.

Importantly: conditions would have to be side-effect free and return a
Bool. They would work just like an assertion, and output their condition on
failure (ie. "Failed precondition: 'configured == false'!").

By side-effect free I mean:
* They would only be able to read properties (instance, or external)
annotated as @non-mutating.
* They can run methods (instance, or external) marked as @non-mutating.
* Things like print(...) cannot be used, the program should be free to
optimise these out.

This annotation may be used like @noescape. It would have to be verified by
the compiler, it may be done automatically (iirc. LLVM has a similar
annotation) but that could lower programmer awareness.

If it's possible to check the conditions at compile-time it would be great
to do so, there's a proposal for compile time evaluation of expressions
which may be relevant.

Another example, you could add assertMainThread() to a `get` precondition
if assertMainThread is marked as side-effect free.

···

On Mon, Dec 14, 2015 at 8:48 AM, Paul Cantrell via swift-evolution < swift-evolution@swift.org> wrote:

>> I know there’s talk on the core team of some more robust property
decoration mechanism. Does this already fold into that effort?
>
> Yes, I believe that this should be covered by that work, which is great.
:slight_smile:

Then I’d plop it in as a use case (admittedly one of the less compelling
ones) for that work, and drop this proposal.

Is any of that work public yet? It sounds exciting. (Apologies if that
question is a repeat; I confess that I have not followed every single
message on this list.)

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


(Etan Kissling) #6

Yay for Design by Contract. (https://www.eiffel.com/values/design-by-contract/introduction/)

Don't forget Invariants, though - these have to hold globally, after each client called method has run to completion.

Would be very nice to get these into the language as it could allow for asserting certain correctness aspects statically.
Also nice to have the contracts show up in a public interface view as an addition to comments,
because these are typically much more precise when writing down a specification.

C#'s CodeContracts are unfortunately not often used, as a binary rewriter needs to be configured as an additional build step.
https://msdn.microsoft.com/en-us/library/dd264808(v=vs.110).aspx?f=255&MSPPError=-2147217396 <https://msdn.microsoft.com/en-us/library/dd264808(v=vs.110).aspx?f=255&MSPPError=-2147217396>

An additional problem with Contracts is that it's not a principle that's understood by everyone.
And to push these through a code base, everyone needs to be willing to apply them properly.

Etan

···

On 13 Dec 2015, at 23:44, Andrew Bennett via swift-evolution <swift-evolution@swift.org> wrote:

Hi, this is an alternative to your proposal, taking into account Chris' comments.

You could add precondition and postcondition on protocol methods and properties, for example:

protocol Configurable {
    typealias Configuration

    var configured: Bool {
        @non-mutating get
        set { precondition { configured == false } }
    }

    // unsure if this syntax is confusing, but it's consistent with get/set
    func configure(configuration: Configuration) {
        precondition { configured == false }
        postcondition { configured == true }
    }
}

The terms precondition, postcondition and @non-mutating are up for debate.

Importantly: conditions would have to be side-effect free and return a Bool. They would work just like an assertion, and output their condition on failure (ie. "Failed precondition: 'configured == false'!").

By side-effect free I mean:
* They would only be able to read properties (instance, or external) annotated as @non-mutating.
* They can run methods (instance, or external) marked as @non-mutating.
* Things like print(...) cannot be used, the program should be free to optimise these out.

This annotation may be used like @noescape. It would have to be verified by the compiler, it may be done automatically (iirc. LLVM has a similar annotation) but that could lower programmer awareness.

If it's possible to check the conditions at compile-time it would be great to do so, there's a proposal for compile time evaluation of expressions which may be relevant.

Another example, you could add assertMainThread() to a `get` precondition if assertMainThread is marked as side-effect free.

On Mon, Dec 14, 2015 at 8:48 AM, Paul Cantrell via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> I know there’s talk on the core team of some more robust property decoration mechanism. Does this already fold into that effort?
>
> Yes, I believe that this should be covered by that work, which is great. :slight_smile:

Then I’d plop it in as a use case (admittedly one of the less compelling ones) for that work, and drop this proposal.

Is any of that work public yet? It sounds exciting. (Apologies if that question is a repeat; I confess that I have not followed every single message on this list.)

Cheers, P
_______________________________________________
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
https://lists.swift.org/mailman/listinfo/swift-evolution