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

Reply via email to