Hi Joe,
> If there's really an independent implementation for each `S: Storage`, then
> you can make `tensorDot` a requirement of `Storage` and avoid the explosion
> that way. Ad-hoc type dispatch by either overloading or if chains should be a
> last resort when protocols really can't model what you're trying to do.
> Ad-hoc overloading wouldn't really save you any work compared to the if
> chain—you'd have all the exact problems you mentioned, having to add an
> overload for every new combo of types, but you'd also have to also think
> about the implicit relationships among the overloads according to the
> language's overloading rules instead of in explicit logic.
You are correct in the number of Impls I need (I was incorrect in that
statement). But I think the if-branches are still problematic. I may
need the same number of functions as branches, but I think the code is
cleaner/easier to read and maintain:
func dot<S:Storage>(_ lhs:Tensor<S>, _ rhs:Tensor<S>) -> Tensor<S>
where S:CBlasStorage<Float> { .. }
func dot<S:Storage>(_ lhs:Tensor<S>, _ rhs:Tensor<S>) -> Tensor<S>
where S:CBlasStorage<Double> { .. }
// NativeStorage has no optimization per type, so we can lump all
of these into a single Impl
func dot<T>(_ lhs:Tensor<NativeStorage<T>>, _
rhs:Tensor<NativeStorage<T>>) -> Tensor<NativeStorage<T>> { .. }
The advantages from this approach are: (a) it has less repeated code
(i.e. I don't have to create both an Impl and an if-branch); (b)
adding a new storage type does require redefining some (if not all) of
the functions (though it provides a nice mechanism for dealing with
defaults), but that code can be kept as a separate module; and (c) You
are effectively rolling your own dynamic dispatch, which is something
I much rather leave up to the compiler to do.
Thanks!
Abe
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution