[proposal] Allow "let" for computed properties which only reference immutable data


(Andru Felipe Zuniga) #1

It would be useful for clarification of a computed property being constant in extensions. For example:

extension SKSpriteNode {
  static let type: String {
    return “Sprite”
  }
}

Andru


(Leonardo Pessoa) #2

If the value of the property is a constant, shouldn't you just declare it
as one? If you have any sort of computation in it, even concatenating two
constant strings, can you really say this is a constant? And you would also
be overloading the compiler into trying to check for every property you use
let if the overall computation is constant or not. IMO, let isn't really
the most appropriate keyword to use for properties.

- Leonardo

···

On 13 May 2016 at 04:44, Andru Felipe Zuniga via swift-evolution < swift-evolution@swift.org> wrote:

It would be useful for clarification of a computed property being constant
in extensions. For example:

extension SKSpriteNode {
        static let type: String {
                return “Sprite”
        }
}

Andru

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


(Leonardo Pessoa) #3

David, I'm thinking about the side effects calling a computed property has
and although I see some use cases for let properties I also see
workarounds. For example, a lazy initialiser will solve the issue of
running a certain code only once and caching its value. I also start to
think that any case in this proposal will be solved by lazy initialisers
thus rendering it unnecessary.

···

On 17 May 2016 at 17:50, David Sweeris <davesweeris@mac.com> wrote:

You can't, if you're extending a pre-existing type.

I'd think that it might be possible to do some caching if the compiler
knows that a computed property is constant, but maybe it doesn't work that
way.

- Dave Sweeris

On May 17, 2016, at 14:40, Leonardo Pessoa via swift-evolution < > swift-evolution@swift.org> wrote:

If the value of the property is a constant, shouldn't you just declare it
as one? If you have any sort of computation in it, even concatenating two
constant strings, can you really say this is a constant? And you would also
be overloading the compiler into trying to check for every property you use
let if the overall computation is constant or not. IMO, let isn't really
the most appropriate keyword to use for properties.

- Leonardo

On 13 May 2016 at 04:44, Andru Felipe Zuniga via swift-evolution < > swift-evolution@swift.org> wrote:

It would be useful for clarification of a computed property being
constant in extensions. For example:

extension SKSpriteNode {
        static let type: String {
                return “Sprite”
        }
}

Andru

_______________________________________________
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


(David Sweeris) #4

`lazy` properties can't be `let`. Personally, I disagree with this — their initial mutation is transparent, and it's conceptually perfectly valid to have a value that's, say, too expensive to calculate during every instance's init and whose value never changes once calculated — but there may well be Very Good Reasons for needing them to be `var`.

- Dave Sweeris

···

On May 17, 2016, at 17:23, Leonardo Pessoa <me@lmpessoa.com> wrote:

David, I'm thinking about the side effects calling a computed property has and although I see some use cases for let properties I also see workarounds. For example, a lazy initialiser will solve the issue of running a certain code only once and caching its value. I also start to think that any case in this proposal will be solved by lazy initialisers thus rendering it unnecessary.

On 17 May 2016 at 17:50, David Sweeris <davesweeris@mac.com> wrote:
You can't, if you're extending a pre-existing type.

I'd think that it might be possible to do some caching if the compiler knows that a computed property is constant, but maybe it doesn't work that way.

- Dave Sweeris

On May 17, 2016, at 14:40, Leonardo Pessoa via swift-evolution <swift-evolution@swift.org> wrote:

If the value of the property is a constant, shouldn't you just declare it as one? If you have any sort of computation in it, even concatenating two constant strings, can you really say this is a constant? And you would also be overloading the compiler into trying to check for every property you use let if the overall computation is constant or not. IMO, let isn't really the most appropriate keyword to use for properties.

- Leonardo

On 13 May 2016 at 04:44, Andru Felipe Zuniga via swift-evolution <swift-evolution@swift.org> wrote:
It would be useful for clarification of a computed property being constant in extensions. For example:

extension SKSpriteNode {
        static let type: String {
                return “Sprite”
        }
}

Andru

_______________________________________________
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


(Leonardo Pessoa) #5

Would it solve the issue if we had lazy let initialisers as I mentioned?

···

-----Original Message-----
From: "David Sweeris" <davesweeris@mac.com>
Sent: ‎18/‎05/‎2016 06:08 AM
To: "Leonardo Pessoa" <me@lmpessoa.com>
Cc: "Swift-evolution" <swift-evolution@swift.org>
Subject: Re: [swift-evolution] [proposal] Allow "let" for computed propertieswhich only reference immutable data

`lazy` properties can't be `let`. Personally, I disagree with this — their initial mutation is transparent, and it's conceptually perfectly valid to have a value that's, say, too expensive to calculate during every instance's init and whose value never changes once calculated — but there may well be Very Good Reasons for needing them to be `var`.

- Dave Sweeris

On May 17, 2016, at 17:23, Leonardo Pessoa <me@lmpessoa.com> wrote:

David, I'm thinking about the side effects calling a computed property has and although I see some use cases for let properties I also see workarounds. For example, a lazy initialiser will solve the issue of running a certain code only once and caching its value. I also start to think that any case in this proposal will be solved by lazy initialisers thus rendering it unnecessary.

On 17 May 2016 at 17:50, David Sweeris <davesweeris@mac.com> wrote:

You can't, if you're extending a pre-existing type.

I'd think that it might be possible to do some caching if the compiler knows that a computed property is constant, but maybe it doesn't work that way.

- Dave Sweeris

On May 17, 2016, at 14:40, Leonardo Pessoa via swift-evolution <swift-evolution@swift.org> wrote:

If the value of the property is a constant, shouldn't you just declare it as one? If you have any sort of computation in it, even concatenating two constant strings, can you really say this is a constant? And you would also be overloading the compiler into trying to check for every property you use let if the overall computation is constant or not. IMO, let isn't really the most appropriate keyword to use for properties.

- Leonardo

On 13 May 2016 at 04:44, Andru Felipe Zuniga via swift-evolution <swift-evolution@swift.org> wrote:

It would be useful for clarification of a computed property being constant in extensions. For example:

extension SKSpriteNode {
        static let type: String {
                return “Sprite”
        }
}

Andru

_______________________________________________
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


(Haravikk) #6

`lazy` properties can't be `let`. Personally, I disagree with this — their initial mutation is transparent, and it's conceptually perfectly valid to have a value that's, say, too expensive to calculate during every instance's init and whose value never changes once calculated — but there may well be Very Good Reasons for needing them to be `var`.

You can kind of do this already by adding private(set) to a lazy property, but yeah, the ability to define it as let would be more concise, work within the same type/file and possibly be more intuitive as well. Really it’s just an indicator to the compiler that a value shouldn’t be mutated so it can stop you, though there are some optimisations that can be done as well, many of these may not apply to lazy properties due to the way that they work.

···

On 18 May 2016, at 10:08, David Sweeris via swift-evolution <swift-evolution@swift.org> wrote:

On May 17, 2016, at 17:23, Leonardo Pessoa <me@lmpessoa.com <mailto:me@lmpessoa.com>> wrote:

David, I'm thinking about the side effects calling a computed property has and although I see some use cases for let properties I also see workarounds. For example, a lazy initialiser will solve the issue of running a certain code only once and caching its value. I also start to think that any case in this proposal will be solved by lazy initialisers thus rendering it unnecessary.

I’m not sure that an immutable lazy property and an immutable computed property are mutually exclusive. I gave an example earlier, though it was based on a misunderstanding of the proposal, but it seems relevant. Imagine if you have a type that has two large immutable array properties, and a computed property that combines them in some way. Do you really want to double the size of your instance by storing that computed value, even after it is no longer being referenced elsewhere? If each array were 512kb, you’d be bloating the type to 2mb to store a value that may never be used again, which is one of the main drawbacks of lazy properties; you could maybe work around this with weak references or something, but that just adds more complexity, whereas a computed property solves the problem by leaving it up to whoever called it to store the value if it makes sense to do-so.

So yeah, I think that both features have their uses, and while computed “let” properties may be relatively niche, the biggest benefit of them is really that they self-advertise that they are unchanging, and that the compiler can help to ensure this is the case, so it’s both a feature for API users to take advantage of, and a defensive feature to help you to code your property.


(Matthew Johnson) #7

`lazy` properties can't be `let`. Personally, I disagree with this — their initial mutation is transparent, and it's conceptually perfectly valid to have a value that's, say, too expensive to calculate during every instance's init and whose value never changes once calculated — but there may well be Very Good Reasons for needing them to be `var`.

You can kind of do this already by adding private(set) to a lazy property, but yeah, the ability to define it as let would be more concise, work within the same type/file and possibly be more intuitive as well. Really it’s just an indicator to the compiler that a value shouldn’t be mutated so it can stop you, though there are some optimisations that can be done as well, many of these may not apply to lazy properties due to the way that they work.

Yep, there are two parts to this. One is that the current 'let' model is extremely strict and thus excludes lazy because it is written to after the instance is initialized. Following from this is the assumptions it allows the optimizer to make.

We discussed relaxing 'let' rules in the memberwise init discussion thread. The core team seems to be willing to consider this with respect to the issue that came up there.

I think a similar case could be made for lazy let, and more generally distinguishing the programmer model of immutability from the optimizer model which may need to rely on immutability of the underlying bits themselves. This distinction would allow the programmer model to be modified to allow for lazy let.

I think it is worth considering (after Swift 3) refining the programmer model to mean the value is always initialized before reading and is never written to after initialization. This allows for implementation flexibility while preserving the semantics visible to users of the type. In that respect it I believe it is similar in spirit to allowing internal references and CoW in the implementation of value semantic types.

It's also worth noting that lazy let is similar to a memoized computed let so it may help address that use case as well. The difference is that with a computed let the compiler would need to guarantee the implementation is a pure function on immutable values.

One related area is weak properties. I believe there is a strong case for something in between 'let' and 'private(set) var' here. It may be desirable to guarantee that your code only initializes the weak property. The only desired value change is when it is zeroed. I'm not sure what this would look like, but maybe 'invisible(set) var' which guarantees that only the Swift runtime will modify the value after initialization.

···

Sent from my iPad

On May 18, 2016, at 8:17 AM, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

On 18 May 2016, at 10:08, David Sweeris via swift-evolution <swift-evolution@swift.org> wrote:

On May 17, 2016, at 17:23, Leonardo Pessoa <me@lmpessoa.com> wrote:

David, I'm thinking about the side effects calling a computed property has and although I see some use cases for let properties I also see workarounds. For example, a lazy initialiser will solve the issue of running a certain code only once and caching its value. I also start to think that any case in this proposal will be solved by lazy initialisers thus rendering it unnecessary.

I’m not sure that an immutable lazy property and an immutable computed property are mutually exclusive. I gave an example earlier, though it was based on a misunderstanding of the proposal, but it seems relevant. Imagine if you have a type that has two large immutable array properties, and a computed property that combines them in some way. Do you really want to double the size of your instance by storing that computed value, even after it is no longer being referenced elsewhere? If each array were 512kb, you’d be bloating the type to 2mb to store a value that may never be used again, which is one of the main drawbacks of lazy properties; you could maybe work around this with weak references or something, but that just adds more complexity, whereas a computed property solves the problem by leaving it up to whoever called it to store the value if it makes sense to do-so.

So yeah, I think that both features have their uses, and while computed “let” properties may be relatively niche, the biggest benefit of them is really that they self-advertise that they are unchanging, and that the compiler can help to ensure this is the case, so it’s both a feature for API users to take advantage of, and a defensive feature to help you to code your property.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution