Why popFirst throws an error, but removeFirst works?
Here's the extension you're probably looking for:
extension Array {
@inlinable
public mutating func popFirst() -> Element? {
if isEmpty {
return nil
} else {
return removeFirst()
}
}
}
The error is improved in Swift 4.2:
error: ios.playground:4:25: error: '[T]' requires the types '[T]' and 'ArraySlice<T>' be equivalent to use 'popFirst'
return elements.popFirst() // ERROR!
^
You get the error because popFirst
is not defined for all Collection
s. It's only defined if the Collection
is its own SubSequence
type. Here's the implementation:
extension Collection where SubSequence == Self {
/// Removes and returns the first element of the collection.
///
/// - Returns: The first element of the collection if the collection is
/// not empty; otherwise, `nil`.
///
/// - Complexity: O(1)
@inlinable
public mutating func popFirst() -> Element? {
// TODO: swift-3-indexing-model - review the following
guard !isEmpty else { return nil }
let element = first!
self = self[index(after: startIndex)..<endIndex]
return element
}
}
The extension requires SubSequence == Self
. Self
(with a capital S) is the type of self
(with a lower-case s). It is the type on which you're calling popFirst
. In your code, Self
is Array<T>
, also spelled [T]
.
The constraint is necessary for this line of popFirst
to compile:
self = self[index(after: startIndex)..<endIndex] ^__^ ^_______________________________________^ | | | This is a SubSequence. | This is a Self.
self[index(after: startIndex)..<endIndex]
is a SubSequence
.
Swift can only assign a SubSequence
to Self
if it knows that Self == SubSequence
.
Array
's SubSequence
type is ArraySlice
. Since ArraySlice
is not the same type as Array
, this extension doesn't apply to Array
.