[swift-evolution] [Discussion] Generic protocols

Anton Zhilin antonyzhilin at gmail.com
Fri Dec 9 13:16:13 CST 2016


A fundamental problem is, how do we get rid of associatedtype duplicates?

A pedantic approach is to add trait operations for conformances:

protocol Constructible {
    associatedtype Value
    init(_ value: Value)
}
struct MyStruct {
    conformance Constructible {
        rename associatedtype ValueInt = Value
    }
    conformance Constructible {
        rename associatedtype ValueString = Value
    }

    typealias ValueInt = Int  // or can be inferred
    init(_ value: Int)

    typealias ValueString = String  // or can be inferred
    init(_ value: String)
}

This way, if there is a if there is a conflicting member, which does not
use any of the associated types, like func foo(), then we can give it
different meanings in different conformances.
Although this approach is the most clean one from theoreticall point of
view, choosing different names for associated types would not look very
good in practise.

One possible solution is to *always* automatically match associatedtypes,
without using typealiases.

protocol ConstructibleFromBoth {
    associatedtype First
    associatedtype Second
    init(first: First)
    init(second: Second)
}
struct MyStruct : ConstructibleFromBoth {
    init(first: Int)
    init(second: Double)
}
extension MyStruct {
    init(first: String)   // now there are 2 distinct conformances
}
extension MyStruct {
    init(second: Float)   // now there are 4 distinct conformances
}

It introduces another potentially exponential algorithm for compiler.
Although, does it? During a conformance test in some generic function,
compiler will need to only find the first match or two.
Anyway, I guess, people would prefer to state explicitly that a type
conforms to multiple versions of a protocol.

Attempt #3. We can resolve the conflict between associated types, if we
delete (if trait sense) confliting associated types from the type. But with
extensions, all associated types can be made conflicting. So there needs to
be some attribute, marking, which of the associated types we don’t want. It
can lie at the place of conformance:

struct MyStruct { }extension MyStruct : @dontCreateTypealiases
(Constructible where Value == Int) { ... }extension MyStruct :
@dontCreateTypealiases (Constructible where Value == String) { ... }//
MyStruct.Value.self  // error, no such type
struct NormalConformanceTest : Constructible { init(_ value: Float)
}NormalConformanceTest.Value.self  //=> Float

Or we can let constrained protocols syntax carry this attribute by default:

extension MyStruct : (Constructible where Value == Int) { ... }//
MyStruct.Value.self  // error, no such type
struct NormalConformanceTest: Constructible { init(_ value: Float)
}NormalConformanceTest.Value.self  //=> Float

The only thing left to solve is generic protocol declaration syntax and
protocol specialization syntax. I’d like to present two ways to do this.
First, taking ideas from Rust:

protocol ContainsCollection<Element> {
    associatedtype CollectionType : Collection where
CollectionType.Element == Element
    func collection() -> CollectionType
}
extension String : ContainsCollection<Character>,
ContainsCollection<UnicodeScalar>, ContainsCollection<CChar> {
    func collection() -> CharacterView
    func collection() -> UnicodeScalarView
    func collection() -> ContiguousArray<CChar>
}

Generic parameters are used to disambiguate between different conformances,
and associated types are just matched. Explicit typealias specifiction is
prohibited, because conflicts.

Second, without modifying current protocol declaration syntax:

protocol ContainsCollection {
    associatedtype Element
    associatedtype CollectionType : Collection where
CollectionType.Element == Element
    func collection() -> CollectionType
}
extension String : ContainsCollection<Element: Character>,
ContainsCollection<Element: UnicodeScalar>,
ContainsCollection<Element: CChar> {
    func collection() -> CharacterView
    func collection() -> UnicodeScalarView
    func collection() -> ContiguousArray<CChar>
}

​
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161209/db516322/attachment.html>


More information about the swift-evolution mailing list