[swift-evolution] [Pitch] Reference storage for enum associated values
Marc Prud'hommeaux
marc at glimpse.io
Fri May 6 09:44:05 CDT 2016
> This means that the ChildGuardianship enum is no longer a real value type with value semantics but a value type with partial reference semantics.
That's already true of any enum that has an associated reference type.
> On May 6, 2016, at 10:26 AM, Michael Peternell <michael.peternell at gmx.at> wrote:
>
>
>> Am 06.05.2016 um 14:08 schrieb Marc Prud'hommeaux <marc at glimpse.io>:
>>
>>
>>> I wonder if there is a practical use-case for this.. Is there? Just curious...
>>
>> Without getting too deep into the weeds of our specific data modal, I'll summarize with "yes". If you need to mix classes with enums and don't have the ability to declare the storage class of the variables, then reference cycles can only be avoided by shimming in some other type that does permit the declaration of the storage type. I would be surprised if I was the only person to encounter this issue; anyone else?
>>
>> It is analogous to the hoops you would need to jump through to define a recursive enum before the "indirect" keyword. As a matter of fact, it is so similar to that case that I wonder if it would make sense to have weak/unowned keywords be before the case name, as with indirect. E.g.:
>>
>> enum ChildGuardianship {
>> unowned case ChildOf(Parent)
>> indirect case GrandChildOf(ChildGuardianship)
>> weak case WardOf(State?)
>> }
>
> sorry, that doesn't really convince me. I don't consider a "ChildGuardianship" enum a practical use-case. The same for "child", "parent", "daughterOf", "sonOf", etc. Or were you programming a kindergarten application to help the kindergarten teachers to bill the parents correctly?
>
> The obvious problem with a storage class in value types is that weak references are by definition mutable: they zero out as soon as the pointee starts deallocating. This means that the ChildGuardianship enum is no longer a real value type with value semantics but a value type with partial reference semantics.
>
> I'm sure there is a practical use-case for this somewhere, but I doubt that it would be generally useful enough to be included into Swift at the language level.
>
> -Michael
>
>>
>> The obvious limitation of this would be that all associated types would be pegged to the same storage class, preventing the ability of having one associated type be weak and another be unowned. This limitation of indirect was mentioned at https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151207/000312.html , but it doesn't seem to have been given much treatment since.
>>
>> -Marc
>>
>>
>>> On May 4, 2016, at 12:25 PM, Michael Peternell <michael.peternell at gmx.at> wrote:
>>>
>>> I wonder if there is a practical use-case for this.. Is there? Just curious...
>>>
>>> -Michael
>>>
>>>> Am 03.05.2016 um 17:07 schrieb Marc Prud'hommeaux via swift-evolution <swift-evolution at swift.org>:
>>>>
>>>>
>>>> The following code currently has a retain cycle and memory leak:
>>>>
>>>> enum ParentChild {
>>>> case SonOf(Parent)
>>>> case DaughterOf(Parent)
>>>> }
>>>>
>>>> class Parent {
>>>> lazy var son: Child = Child(parentChild: .SonOf(self))
>>>> lazy var daughter: Child = Child(parentChild: .DaughterOf(self))
>>>> deinit { print("deinit Parent") }
>>>> }
>>>>
>>>> class Child {
>>>> var parentChild: ParentChild
>>>> init(parentChild: ParentChild) {
>>>> self.parentChild = parentChild
>>>> }
>>>> deinit { print("deinit Child") }
>>>> }
>>>>
>>>>
>>>> do {
>>>> let parent = Parent()
>>>> parent.son
>>>> parent.daughter
>>>> }
>>>>
>>>>
>>>> Child.parentChild cannot be declared unowned because ParentChild is a value type. I propose adding the ability to declare the reference storage class for an enum's associated value, like so:
>>>>
>>>> enum ParentChild {
>>>> case SonOf(unowned Parent)
>>>> case DaughterOf(unowned Parent)
>>>> }
>>>>
>>>> The only current alternative is to have some intermediate reference type that itself holds the reference, akin to the old "Box" type that we used to use to work around enum limitations. E.g., this is our current cumbersome work-around:
>>>>
>>>> /// An unowned reference to a value, which is useful for maintaining parent-child relations through value types like enums
>>>> public struct UnownedRef<T: AnyObject> {
>>>> public unowned let value: T
>>>> public init(_ value: T) { self.value = value }
>>>> }
>>>>
>>>> enum ParentChild {
>>>> case SonOf(UnownedRef<Parent>)
>>>> case DaughterOf(UnownedRef<Parent>)
>>>> }
>>>>
>>>>
>>>> class Parent {
>>>> lazy var son: Child = Child(parentChild: .SonOf(UnownedRef(self)))
>>>> lazy var daughter: Child = Child(parentChild: .DaughterOf(UnownedRef(self)))
>>>> deinit { print("deinit Foo") }
>>>> }
>>>>
>>>> class Child {
>>>> var parentChild: ParentChild
>>>> init(parentChild: ParentChild) {
>>>> self.parentChild = parentChild
>>>> }
>>>>
>>>> deinit { print("deinit Child") }
>>>> }
>>>>
>>>> The storage type of an enum would, of course, be limited to reference types, and when the storage class is weak, it would require that the stored type be Optional, just like when declaring a weak variable.
>>>>
>>>> What do people think?
>>>>
>>>> -Marc
>>>>
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>
>
More information about the swift-evolution
mailing list