2

I'm trying to write a generic Swift wrapper for some of the vector operations in the Accelerate vDSP framework and I'm running into a problem calling the functions in a generic way.

My vector struct looks like:

public struct Vector<T> {
  let array: [T]
  public static func add(_ a: [T], _ b: [T]) -> [T] {
    vDSP.add(a, b)
  }

  public static func + (_ lhs: Self , _ rhs: Self) -> Self {
    Self.add(lhs.array, rhs.array)
  }
}

The problem is the add function is overloaded to either take Floats and return Floats or take Doubles and return Doubles. Since the type isn't known at compile time I get an error No exact matches in call to static method 'add'

The only way I've found to get around this is to explicitly check the type before the call and cast:

public static func add(_ a: [T], _ b: [T]) -> [T] {
  if T.self is Float.Type {
    return vDSP.add(a as! [Float], b as! [Float]) as! [T]
  } else {
    return vDSP.add(a as! [Double], b as! [Double]) as! [T]
  }
}

or to use constrained methods

public static func add(_ a: T, _ b: [T]) -> [T] where T == Float { vDSP.add(a, b) }
public static func add(_ a: T, _ b: [T]) -> [T] where T == Double { vDSP.add(a, b) }

Both of these lead to uncomfortable code duplication, and what's more if I had more than two types (for example if supported is added for the upcoming Float16 type) I'd need to keep adding more and more cases. The latter approach seems especially bad since the method bodies are identical.

I'd like to be able to do something like vDSP.add<T>(a, b) but it seems Swift doesn't support this. Is there some other way to acheive this and avoid the code duplication?

jkanji
  • 21
  • 1
  • Ideally, you'd just constraint `T` to `FloatingPoint` but it looks like that won't work here and you need to be explicit about the types upfront. – Suyash Srijan Jul 05 '20 at 20:11
  • You really have to ask yourself if generics is a tool that you'd use here, if the underlying API restricts it `Float` and `Double`. Does your type make sense for types other than these two, like say random type `Foo`? And if not, then is there a meaningful constrain where you could still reason in generics types? – New Dev Jul 05 '20 at 20:51
  • @NewDev I'm intending on adding support for more than just Float and Double (eg Ints or Reals from the swift-numerics package) but I want to use the Accelerate methods if they're available. Right now I'm putting the Accelerate calls into an extension constrainted to a custom protocol that only Float and Double conform to, while the base type is constrained to `Numeric` – jkanji Jul 05 '20 at 21:12

0 Answers0