2

If I remove elements from an array and store it in a variable like this:

let lastFive = myArray.suffix(5)

or this:

let lastFive = myArray.dropLast(5)

lastFive will be Array<SomeType>.SubSequence instead of the element type SomeType. How do I make lastFive become the [Element] rather than a SubSequence?

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
Joakim Sjöstedt
  • 824
  • 2
  • 9
  • 18

1 Answers1

1

I like to use this extension:

extension Sequence {
    func asArray() -> [Element] {
        return Array(self)
    }
}

That said, both the Collection and Sequence protocols define a sequence() method.

Sequence.prefix() returns [Element] while Collection.prefix() returns a SubSequence.

Given an Array defined as follows, we can do some interesting things.

let myArray = [1, 2, 3, 4, 5]

The following works because the compiler knows to use the Sequence version of suffix().

func lastFive() -> [Int] {
    return myArray.suffix(5)
}

Here I'm just using the extension from above.

func lastFive2() -> [Int] {
    return myArray.suffix(5).asArray()
}

The following also works because the compiler knows to use the Sequence version of suffix().

func lastFive3() -> [Int] {
    let suffix: [Int] = myArray.suffix(5)
    return suffix
}

This does not compile because the compiler assumes you want to use the Collection version of suffix().

func doesNotCompile() -> [Int] {
    let suffix = myArray.suffix(5)
    return suffix
}
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
Rob C
  • 4,877
  • 1
  • 11
  • 24
  • I would make it a computed property. Btw you are not casting anything: `var array: [Element] { .init(self) }` – Leo Dabus Jan 22 '22 at 02:31
  • 1
    Funny thing is that when it is a subsequence casting instead of explicitly setting the resulting type works as well. `let suffix = myArray.suffix(5) as [Int]` – Leo Dabus Jan 22 '22 at 02:39
  • And when the collection is a string `str.suffix(5) as [Character]`works while `str.suffix(5) as String` doesn't. – Leo Dabus Jan 22 '22 at 02:53
  • @LeoDabus I tend to prefer defining methods over computed properties where implementations create a new instance. But I do like the property syntax. I am still super curious how this auto conversion (if that is the right word to use) from SubSequence to Array is happening. Same goes for the casting you pointed out in your second comment. I dug through the docs and SO but found nothing. – Rob C Jan 22 '22 at 02:53
  • I did try to go to the definition of that `func suffix(_ maxLength: Int) -> [Element]` as well but I couldn't find it – Leo Dabus Jan 22 '22 at 02:57
  • Actually just found it https://github.com/apple/swift/blob/main/stdlib/public/core/Sequence.swift – Leo Dabus Jan 22 '22 at 02:58
  • `public __consuming func suffix(_ maxLength: Int) -> [Element] {` – Leo Dabus Jan 22 '22 at 02:59
  • Yeah, I just found it too. Sequence and Collection both define a suffix method with different return types. – Rob C Jan 22 '22 at 02:59
  • Note that it DOES initialize a new array when returning the result – Leo Dabus Jan 22 '22 at 03:01
  • So you know already how it works. `Collection` method returns a `SubSequence`. `Sequence` method returns `[Element]` . – Leo Dabus Jan 22 '22 at 03:08
  • Depending on the resulting type it will call one or another. – Leo Dabus Jan 22 '22 at 03:09
  • Yep, I just updated my answer. – Rob C Jan 22 '22 at 03:09
  • The main point here is that the compiler wont create a new collection unless you explicitly set the resulting type. – Leo Dabus Jan 22 '22 at 03:15
  • @LeoDabus BTW, it's not that the compiler won't create a new collection unless you ask for it (because it has no idea what that means), it's that during overload resolution, the compiler will prefer a method from a more specific protocol conformance (`Collection` is more specific than `Sequence`). You can override this by explicitly setting the type. See a similar case in https://stackoverflow.com/questions/68332664/is-swift-array-reversedn-efficient-or-not/68332748#68332748 [This _may_ be what you meant, but just to be more precise...] – Itai Ferber Jan 23 '22 at 13:56