I don't understand how this change would cause method dispatch to invoke a 
different prototype.  Specialization in either language mentioned doesn't do 
that.

~Robert Widmann

2017/02/05 11:28、Abe Schneider via swift-evolution <[email protected]> 
のメッセージ:

> Hi all,
> 
> The current behavior of generics in Swift causes it lose type information at 
> compile time due to the desire of maintaining a single version of the 
> function. This runs counter to how c++ works, which creates a new copy of a 
> function per type, but preserves information to be preserved. This can cause 
> unexpected behavior from the user’s perspective:
> 
>    protocol DispatchType {}
>    class DispatchType1: DispatchType {}
> 
>    func doBar<D:DispatchType>(value:D) {    
>        print(“General function called")
>    }
> 
>    func doBar(value:DispatchType1) {
>        print("DispatchType1 called")
>    }
> 
>    func test<D:DispatchType>(value:D) {
>        doBar(value: value)
>    }
> 
>    test(value: d1)     // “General function called”, but it’s not obvious why
> 
> 
> The suggested method to get around this issue is to use a protocol to create 
> a witness table, allowing for runtime dispatch. However, this approach is not 
> ideal in all cases because: (a) the overhead of runtime dispatch may not be 
> desirable, especially because this is something that can be determined at 
> compile time; and (b) there are some designs in which this behavior can 
> complicate things.
> 
> One example of a design where this behavior can be problematic is when a 
> protocol is used to determine what functions get dispatched:
> 
>    protocol Storage { … }
>    class Tensor<S:Storage> { … }
> 
>    class CBlasStorage: Storage { … }
>    class OpenCLStorage: Storage { … }
> 
>    func dot<S:Storage>(_ lhs:Tensor<S>, _ rhs:Tensor<S>) -> Tensor<S> { … }
> 
>    // like behavior, these will not work if called from another generic 
> function (but will work for non-generic functions)
>    func dot<S:Storage>(_ lhs:Tensor<S>, _ rhs:Tensor<S>) -> Tensor<S> where 
> S:CBlasStorage { … }
>    func dot<S:Storage>(_ lhs:Tensor<S>, _ rhs:Tensor<S>) -> Tensor<S> where 
> S:OpenCLStorage { … }
> 
> In this case, depending on the underlying storage, we want an optimized 
> version of `dot` to be called. To make this work correctly we can add static 
> methods to `Tensor`, but this has several drawbacks: (a) it makes the 
> `Tensor` class monolithic, every possible method must be determine a priori 
> and be defined in the class; (b) it doesn’t allow new methods to be added 
> Tensor without touching the main class; and (c) it unnecessarily forces users 
> to user the more verbose `Tensor.dot(a, b)`.
> 
> Point (a) in theory could be made better by creating a `TensorOps` protocols. 
> However, because type constraints cannot currently be placed on extensions, 
> it is not currently possible to implement.
> 
> 
> One potential solution would be to add/extend an attribute for generic 
> functions that would force multiple versions of that function to be created. 
> There is already there is a `@_specialize` attribute, but you have to: (a) 
> manually write out all the cases you want to cover; and (b) only affects the 
> compiled code, which does not change this behavior. Due to the fact that 
> `@_specialize` exists, I’m going to assume it wouldn’t be a major change to 
> the language to extend the behavior to compile-time dispatch.
> 
> 
> Thanks!
> Abe
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to