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

Антон Жилин antonyzhilin at gmail.com
Thu Jun 9 11:12:16 CDT 2016


When I said that the problem would exist internally, I meant that there
would still be two conflicting associatedtype declarations inside MyType.
This can be perfectly solved by conformance-with-renaming. Example:

extension MyType : Computer {
    from Computer rename Internal to Internal1
    associatedtype Internal1 = Int
}
extension MyType : Computer {
    from Computer rename Internal to Internal2
    associatedtype Internal2 = Double
}

Then MyType should play well both in contexts of  T: Computer where
Internal == Int  and  T: Computer where Internal == Double.

It potentially convers a broad range of conflicts, such as conflicting
functions and conflicting properties.
We could include composition operations of traits in Swift's protocols,
most notably, rename and exclude.
Niall Young <niall at iinet.net.au> is working on this problem, but his
proposal is going to add new separate "trait" declarations for that, a
decision which I don't quite understand.

And still I think I'll propose generic protocols if noone does that before.

- Anton

2016-06-09 18:37 GMT+03:00 Vladimir.S <svabox at gmail.com>:

> 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
>>
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160609/71e0f683/attachment.html>


More information about the swift-evolution mailing list