[swift-evolution] [Bug?] Reference types and mutating methods

T.J. Usiyan griotspeak at gmail.com
Sat Apr 30 10:38:25 CDT 2016


The problem here seems to be with using the default implementation
provided. If you override `append` in ObservedArray, the compiler allows
it. That seems 'safe' but odd at first. I wouldn't *want* to implement
every mutating method, but that is the current solution. I haven't puzzled
out the reasoning behind this myself.


``` swift
class ObservedArray<T> : ArrayLiteralConvertible {
    var value: [T]
    init(value: [T]) {
        self.value = value
    }
    required init() {
        self.value = []
    }

    required convenience init(arrayLiteral elements: T...) {
        self.init(elements)
    }

}

extension ObservedArray {
    typealias Index = Int

    var startIndex: Index {
        return value.startIndex
    }

    var endIndex: Index {
        return value.endIndex
    }

    subscript(position: Index) -> T {
        return value[position]
    }

}

extension ObservedArray : RangeReplaceableCollectionType {
    typealias Generator = IndexingGenerator<[T]>

    func generate() -> Generator {
        return value.generate()
    }
}

extension ObservedArray {
    func replaceRange<C : CollectionType where C.Generator.Element ==
Generator.Element>(subRange: Range<Index>, with newElements: C) {
        value.replaceRange(subRange, with: newElements)
    }

    func append(newElement: T) { // <- adding this makes it work
        value.append(newElement)
    }
}

let array: ObservedArray<String> = []
array.append("1")


```




On Sat, Apr 30, 2016 at 7:52 AM, James Froggatt via swift-evolution <
swift-evolution at swift.org> wrote:

> I don't believe this has been addressed, please correct me if I'm wrong.
>
> --My Situation--
> I've recently been working on an observable collection type. Because each
> stores ‘subscriptions’ to changes that occur, it made sense to me that this
> should be a reference type, so subscriptions can't be copied with the
> values themselves.
>
> I have made this class conform to RangeReplaceableCollectionType,
> providing it with all the standard collection functions. I do the following:
>
> let array: ObservedArray<String> = []
> array.append("1") //Error: Cannot use mutating member on immutable value:
> ‘array’ is a ‘let’ constant
>
> I have to make the reference immutable just to use my new collection type?
> This is a bit of a deal-breaker.
>
> --The Problem--
> Mutating methods allow ‘self’ to be reassigned, which is just another way
> to mutate a value type. However, reassigning ‘self’ has a special meaning
> to reference types, which is presumably the reason they are disallowed in
> classes.
>
> However, classes can conform to protocols with mutating methods, leading
> to the compiler disallowing calls to mutating methods for ‘let’ values of
> type ‘protocol<MutatingProtocol, AnyObject>’, which can be an annoyance in
> generic code. In addition, classes can inherit mutating methods from
> protocol extensions, leading to the behaviour I describe above.
>
> Is this intentional behaviour? Am I going about this in the wrong way? Or
> is this really an omission in the language?
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160430/7766324a/attachment.html>


More information about the swift-evolution mailing list