Why `let anInt: Int = Double.pi` is not allowed but `var aaa: [Int] = [1, 2, 3, 4, 5, 6, 7].reversed()` is okay?

?

I guess the second expresión implicitly call the suitable Array.init() to create a new array.

Why the first expression doesn’t do the implicit conversion but the second one does.

What’s the different in these two cases to have two different treatment ?

Not quite. This isn't a question of implicit conversion, but of overloading at different points in the Collection hierarchy, along with the (sometime surprising) impact of Swift's overload resolution.

Sequence has the a method Sequence.reversed() -> [Element] which returns an Array. This is the only thing you can really do with something you can't iterate backwards – you have to slurp up all the elements into a buffer, then reverse it.

BidirectionalCollection can do better. It can return a lazy wrapper, because you can wrap a BiDi collection and then serve up its elements in reverse order.

If you just write let reversed = arrrayOfInt.reversed() it'll call the most specific method, so reversed will be a ReversedCollection<[Int]>.

But if you force the return value to [Int], the solver will discard that possibility, and it falls back to a less favored option that does work, which is the version on Sequence that returns an [Int].

So there is no conversion happening here – just a different method than maybe was expected being called.

5 Likes

:pray:

Why with this:

var aaa = [1, 2, 3, 4, 5, 6, 7].reversed()  // don’t force it to [Int]
let xxx = aaa.popLast()  // compile error here

I get error:

Referencing instance method 'popLast()' on 'BidirectionalCollection' requires the types 'ReversedCollection<[Int]>' and 'ReversedCollection<[Int]>.SubSequence' (aka 'Slice<ReversedCollection<Array>>') be equivalent

How can I overcome this without forcing it to be a [Int], incurring copying? How can I operate on ReversedCollection<[Int]>?

Create a subsequence of the reversed collection:

    let reversed = [1, 2, 3, 4, 5, 6, 7].reversed()
    var slice = reversed[...]
    let element = slice.popLast()

Subsequences can have their last element popped easily because it's just a question of reducing the bounds of the slice, not actually mutating the underlying base collection.

3 Likes

(the rather enigmatic error message is telling you that you can't pop the end off an arbitrary collection, but you can pop the end of a collection who's subsequence is Self)

1 Like

I've become used to this workaround, from running into this problem frequently enough, but I still wish it wasn't necessary. It does feel very hacky to do things like [...] when you don't explicitly care about the types involved, you just want something to work, like popLast.

I don't have any specific ideas for how to improve that, though. :pensive: