Swift 5 SIMD3 no longer a Collection?

I just downloaded Xcode 10.2 beta 4 to start porting my Apps to Swift 5. In Swift 4.x SIMD types like double3 or float4 conformed to the Collection protocol allowing code such as:


let v: double3

var va = v.map({ abs($0) })

let vs = va.sorted()


Is this intentionally in Swift 5 or just not yet finished? I tried to extend SIMD3 generic type in Swift 5 to conform to the Collection protocol but got some errors, I do not know how to solve:


extension SIMD3 : Collection {

public var startIndex: Int {

return 0

}

public var endIndex: Int {

return 2

}

public func index(after i: Int) -> Int {

return i+1

}

}


error: type 'SIMD3<Scalar>' does not conform to protocol 'Collection'

extension SIMD3 : Collection {

^

Swift.Collection:13:20: note: ambiguous inference of associated type 'Indices': 'DefaultIndices<SIMD3<Scalar>>' vs. 'Range<Int>'

associatedtype Indices : Collection = DefaultIndices<Self> where Self.Indices == Self.Indices.SubSequence

^

Swift.Collection:2:27: note: matching requirement 'indices' to this declaration inferred associated type to 'DefaultIndices<SIMD3<Scalar>>'

@inlinable public var indices: DefaultIndices<Self> { get }

^

Swift.SIMD:2:16: note: matching requirement 'indices' to this declaration inferred associated type to 'Range<Int>'

public var indices: Range<Int> { get }



Any help would be appreciated. Best, Fritzt

Accepted Reply

Is this intentionally in Swift 5 or just not yet finished?


I could not find any articles stating wheather this is intentional or not. You should better try writing a feature request using Bug Reporter.


And as far as tried, this code makes `SIMD3` conform to `Collection`:

extension SIMD3: Collection {
    
    public typealias Indices = Range<Int>
    
    public var startIndex: Int {
        return 0
    }
    public var endIndex: Int {
        return self.scalarCount
    }
    public func index(after i: Int) -> Int {
        return i+1
    }
}


Or something like this:

extension SIMD {
    
    public typealias Indices = Range<Int>
    
    public var startIndex: Int {
        return 0
    }
    public var endIndex: Int {
        return self.scalarCount
    }
    public func index(after i: Int) -> Int {
        return i+1
    }
}
extension SIMD2: Collection {}
extension SIMD3: Collection {}
extension SIMD4: Collection {}
extension SIMD8: Collection {}
extension SIMD16: Collection {}
extension SIMD32: Collection {}
extension SIMD64: Collection {}


By the way, `v.map({ abs($0) })` returns `[Double]`, so it may not be as efficient as `abs(v)`.

Replies

Is this intentionally in Swift 5 or just not yet finished?


I could not find any articles stating wheather this is intentional or not. You should better try writing a feature request using Bug Reporter.


And as far as tried, this code makes `SIMD3` conform to `Collection`:

extension SIMD3: Collection {
    
    public typealias Indices = Range<Int>
    
    public var startIndex: Int {
        return 0
    }
    public var endIndex: Int {
        return self.scalarCount
    }
    public func index(after i: Int) -> Int {
        return i+1
    }
}


Or something like this:

extension SIMD {
    
    public typealias Indices = Range<Int>
    
    public var startIndex: Int {
        return 0
    }
    public var endIndex: Int {
        return self.scalarCount
    }
    public func index(after i: Int) -> Int {
        return i+1
    }
}
extension SIMD2: Collection {}
extension SIMD3: Collection {}
extension SIMD4: Collection {}
extension SIMD8: Collection {}
extension SIMD16: Collection {}
extension SIMD32: Collection {}
extension SIMD64: Collection {}


By the way, `v.map({ abs($0) })` returns `[Double]`, so it may not be as efficient as `abs(v)`.

Awesome, many thanks! I ended up using your suggestion of extending the SIMD protocol and extending the generics by the Collection protocol like this:


extension SIMD {
  public typealias Indices = Range
  public var startIndex: Int {
    return 0
  }
  public var endIndex: Int {
    return scalarCount
  }
  public func index(after i: Int) -> Int {
    return i+1
  }
}
extension SIMD4 : Collection {}
extension SIMD3 : Collection {}
extension SIMD2 : Collection {}


I've filed a bug report (48859531).

SIMD types are not expected to conform to

Collection
. There’s been an extended discussion of this over on Swift Forums but, alas, I’ve not been paying enough attention to explain the rationale behind that decision.

With regards the code you posted, I want to point out two things:

  • OOPer wrote:

    By the way,

    v.map({ abs($0) })
    returns
    [Double]
    , so it may not be as efficient as
    abs(v)
    .

    and that seems pretty relevant to me. If you're going to do an

    abs
    on a vector, it’d be best to do that as a SIMD operation.
    import simd
    let v = double3(-2.0, 3.0, -1.0)
    let va = abs(v)
    print(va)   // -> IMD3<Double>(2.0, 3.0, 1.0)

    .

  • If you want to convert a vector to an array of elements (so you can sort that array), you can map over the

    indices
    property. To continue the above example:
    let vas = va.indices.map { va[$0] }.sorted()
    print(vas)  // -> [1.0, 2.0, 3.0]

    .

Finally, adding your own conformance to

Collection
seems like a step in the wrong direction here.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"