[swift-users] inout generic struct parameter error

Ben Cohen ben_cohen at apple.com
Sun Jan 1 18:52:45 CST 2017


Hi Georgios,

Yes, that isn’t the best of error messages.

The problem is that makeIterator() is not a mutating function, so inside it all properties are treated as immutable. This means you aren’t allowed to pass them into functions as inout arguments. It’s essentially the same as this:

func takesInout(i: inout Int) { i += 1 }

struct S {
    var x: Int
    func nonmutating() {
        takesInout(i: &x)
    }
}
// Error: Cannot pass immutable value as inout argument: 'self' is immutable
// Fix-it: Mark method mutating to make 'self' mutable

Ideally you’d get an error message along these lines for your case but it looks like it’s failing.

So, you might consider making makeIterator mutating like the Fix-it suggests, which would allow you to pass its members as inout arguments:

    mutating public func makeIterator() -> WeakArrayIterator<T> {

But if you do this you will get a different compiler error, because your struct will no longer conform to Sequence, which requires makeIterator to be non-mutating. This is important, especially assuming your array is eventually going to conform to Collection as well. One of the requirements of collections is that they give an accurate count, but in the case of your array, the count returned might be different (greater) than the number of elements returned when you actually iterate the array, and this is not allowed (you may find that some standard library functions will trap when they discover that this has happened).

HTH,
Ben


> On Jan 1, 2017, at 10:48 AM, 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.
> 
> thanks,
> -g.
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170101/21a33657/attachment.html>


More information about the swift-users mailing list