[swift-evolution] [Draft] Allow multiple conformances to the same protocol

Vladimir.S svabox at gmail.com
Thu Jun 9 10:37:13 CDT 2016


Hmm.. In case we *can* have generic `protocol Computer*<Internal>*{..}` - 
then yes, it seems like a best solution(generic protocols and using of 
generic types).

As for hypothetical solution without generic protocol, then we need to 
separate two `Internal` assotiated types (i.e. separate implementation of 
Computer(Internal=Int) and Computer(Internal=Double) protocols).  I.e. it 
seems like the same protocol with different assotiated type should be 
treated as different protocol.

 > func test<T: Computer>(input: inout T) {
 >     let internal: T.Internal = input.prepare()
 >     input.compute(internal)
 > }
 >
 > What is T.Internal , Int or Double? I showed the problem very eplicitly,
 > but it would exist hidden in a much greater number of cases.

As I see the situation: our type implemented two protocols, one Computer 
with Internal = Int, and second with Internal = Double. So, in case we 
*can* implement the same protocol with different assotiated types - we 
*must* have a requirement and the ability to separate these implementation 
*before* calling this func.
I.e. we should be forced to call `test` simething like this:

test(MyType() as Computer where .Internal = Int)
// just MyType() will produce something like "multiply conformance to 
Computer with different assotiated types, need explicit cast to one of 
concrete implementation"

This is just abstract thoughts with abstract syntax, don't know if there is 
something useful in them at all :-)

On 09.06.2016 18:01, Антон Жилин wrote:
> A problem with my solution is that there is a conflict between
> associatedtype declarations inherited from From<Int> and From<Double>.
> Or in your example, associatedtype Element = Int  and  associatedtype
> Element = String  are in conflict.
> Another example:
>
> protocol Computer {
>     associatedtype Internal
>     mutable func prepare() -> Internal
>     mutable func compute(input: Internal)
> }
>
> extension MyType : Computer<Int> { }
> extension MyType : Computer<Double> { }
>
> func test<T: Computer>(input: inout T) {
>     let internal: T.Internal = input.prepare()
>     input.compute(internal)
> }
>
> What is T.Internal , Int or Double? I showed the problem very eplicitly,
> but it would exist hidden in a much greater number of cases.
>
> It's not that such resolution is impossible, but solution of Chris does not
> have this problem at all: generic types do not create associated type
> requirements.
> In this case, there is no ambiguity:
>
> protocol Computer<Internal> {
>     mutable func prepare() -> Internal
>     mutable func compute(input: Internal)
> }
>
> extension MyType : Computer<Int> { }
> extension MyType : Computer<Double> { }
>
> func test<I, T: Computer<I>>(input: inout T) {
>     let internal: I = input.prepare()
>     input.compute(internal)
> }
>
> test(MyType() as Computer<Int>)  // no ambiguity
> test(MyType() as Computer<Double>)  // no ambiguity
>
> - Anton
>
> 2016-06-09 17:25 GMT+03:00 Vladimir.S <svabox at gmail.com
> <mailto:svabox at gmail.com>>:
>
>     I like the idea as associatedtype is playing the role of generic type
>     and in extension we conforms to the protocol with some specific generic
>     type as associated type.
>
>     I mean the first idea probably could be
>     protocol From<T> {
>          init(_ value: T)
>      }
>     but "protocols do not allow generic parameters; use associated types
>     instead", so it seems natural to express concrete type as associated
>     type for protocol in generic syntax <Type>
>
>     Probably alternative syntax could look like:
>
>     extension Int : From where .FromType = Float { }
>
>     Also, it seems like this proposal could help to solve a problem with
>     the same name of associated type in different protocols:
>
>     protocol One {
>          associatedtype Element
>          func foo(t: Element)
>      }
>
>     protocol Two {
>          associatedtype Element
>          func bar(t: Element)
>      }
>
>     struct OneTwo : One, Two {
>         func foo(t: Int) {}
>         func bar(t: String) {}
>     }
>     // type 'OneTwo' does not conform to protocol 'Two'
>     // candidate has non-matching type '(t: String) -> ()' [with Element =
>     Element]
>
>     So, as I understand, will be possible
>     struct OneTwo : One, Two<String> {
>         func foo(t: Int) {} // OneTwo.Element will be Int
>         func bar(t: String) {}
>
>     }
>
>     On 08.06.2016 22:07, Антон Жилин via swift-evolution wrote:
>
>         ==Motivation==
>
>         protocol From {
>             associatedtype FromType
>             init(_ value: FromType)
>         }
>
>         The problem is, one type cannot implement multiple From "conversions".
>
>         ==Proposed solution==
>
>         Allow specifying all associated types using generic syntax.
>
>         extension Int : From<Float> { }
>         extension Int : From<Double> { }
>
>         This is only allowed in conformance declarations.
>
>         ==Future directions==
>
>         We can replace all *Convertible protocols with From and Into, which
>         will be
>         defined similarly to Rust.
>
>         - Anton
>
>
>         _______________________________________________
>         swift-evolution mailing list
>         swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>         https://lists.swift.org/mailman/listinfo/swift-evolution
>
>


More information about the swift-evolution mailing list