[swift-users] inout generic struct parameter error

David Sweeris davesweeris at mac.com
Sun Jan 1 15:20:18 CST 2017


> On Jan 1, 2017, at 10:48, Georgios Moschovitis via swift-users <swift-users at swift.org> wrote:
> 
> While getting my feet wet with Swift, I am still surprised with type-system ‘quirks’ here and there.
> 
> I tried to implement a simple array of weak references:
> 
> public struct WeakArrayIterator<T: AnyObject>: IteratorProtocol {
>     var array: [Weak<T>]
>     var index = 0
>     
>     init(_ array: [Weak<T>]) {
>         self.array = array
>     }
>     
>     mutating public func next() -> T? {
>         while index < array.count && array[index].value == nil {
>             // Remove weak references invalidated by ARC.
>             array.remove(at: index)
>         }
>         
>         if index < array.count {
>             let value = array[index].value
>             index += 1
>             return value
>         } else {
>             return nil
>         }
>     }
> }
> 
> public struct WeakArray<T: AnyObject>: Sequence {
>     var weakRefs: [Weak<T>]
>     
>     init() {
>         weakRefs = []
>     }
>     
>     public var count: Int {
>         return weakRefs.count
>     }
> 
>     public subscript(index: Int) -> T? {
>         get {
>             return weakRefs[index].value
>         }
>         
>         set(value) {
>             weakRefs[index] = Weak(value!)
>         }
>     }
>     
>     mutating public func append(_ value: T) {
>         weakRefs.append(Weak(value))
>     }
>     
>     @discardableResult
>     mutating func remove(at index: Int) -> T? {
>         return weakRefs.remove(at: index).value
>     }
>     
>     public func makeIterator() -> WeakArrayIterator<T> {
>         return WeakArrayIterator(weakRefs)
>     }
> }
> 
> This kinda works but because we pass a struct at:
> 
>         return WeakArrayIterator(weakRefs)
> 
> the ‘garbage collection’ at:
> 
>             // Remove weak references invalidated by ARC.
>             array.remove(at: index)
> 
> doesn’t affect the original array.
> 
> I tried changing to this:
> 
> public struct WeakArrayIterator<T: AnyObject>: IteratorProtocol {
>     ...    
>     init(_ array: inout [Weak<T>]) {
>         self.array = array
>     }        return WeakArrayIterator(&weakRefs)
>> 
> public struct WeakArray<T: AnyObject>: Sequence {
>     return WeakArrayIterator(&weakRefs)
> 
> but I get this strange (to me) error:
> 
> Cannot convert value of type ‘[Weak<T>]’ to expected argument type ‘[Weak<_>]’
> 
> I even get the fix-it suggestion:
> 
> Fix-it Insert “as [Weak<_>]”
> 
> which does not even compile!
> 
> I would appreciate it if someone could explain me this cryptic error and maybe provide some pointers about how to properly/efficiently implement a WeakArray.

FWIW, whenever I've encountered that message, it's been a sign that I'm either stretching type system a bit past what it can handle, or I've got a subtle error elsewhere in my code...

The passed-in array isn't going to get modified though, because you never change it. At least semantically speaking, arrays in swift are pass-by-value, so when you assign it to your struct's local storage and then later modify the *struct's* variable, only the local copy gets affected. If you want to mutate the passed-in array, you'll have to do it in the function you pass it to.

- Dave Sweeris
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170101/95ba77ae/attachment.html>


More information about the swift-users mailing list