Things will get better once we have existentials.
> On 29 Jun 2016, at 08:49, Robert Widmann via swift-evolution > <[email protected]> wrote: > > Yes, the restriction "sucks", but it is there for a reason. A protocol is > not just a convenient collection of methods and properties you can generalize > over, it's a contract. Each tells you something about what its implementers > have to do before they can call themselves 'Equatable' or 'MyProtocol' etc. > Let's see what happens at a very high level if we relax this constraint for > Equatable as you have written here. > > protocol Equatable { > func ==(_: Equatable, _: Equatable) -> Bool > } > > And now two implementers (implementation abbreviated for brevity) > > extension String: Equatable {} > extension Int: Equatable {} > > // ... > > Given this definition, the following typecheck > > 1 == 2 // false > "A" == "A" // true > 1 == "1" // ? > "ABC" == 123 // ? > > Being Equatable suddenly must include a component of self-identity. We have > to be able to constrain the implementation to only those Equatable things > that look like ourselves. Thus, Self constraints. Because 'MyProtocol' is > not defining a protocol for things that understand equality, it is defining > an equivalence relation over all possible implementations of ==, and that > means that anything goes. > > So you might modify this to use associated types then. What about an > iteration that asks the implementer to specify the type made in the > comparison? > > protocol Equatable { > associatedtype Comparator > func ==(_: Equatable.Comparator, _: Equatable.Comparator) -> Bool > } > > This also solves nothing. You can't actually constrain the associated types > here with a needed equality constraint. You can only push the problem down a > needless level of abstraction. > > Yes it's a pain to have to use Generics to reify restricted protocols. Yes > it's a pain to give up use of protocol-ified collections. Yes it's not > immediately obvious why these restrictions are in place. But to drop them > would severely dilute the intended semantics and use of protocols that > require knowledge of their reifications. Unfortunately, equality just > happens to be one such protocol. > > There are ways around this. If you have a sealed hierarchy you can write an > enum that enumerates all possible implementations and delegates it's > equatable conformance out to them. Often, identity can be found elsewhere in > a type. For example, a hypothetical 'UUIDable' protocol could specify it's > implementers produce a String UUID that could be stored in collections > instead of UUIDable types themselves. For most other cases try to > re-evaluate. Why do you need to generalize over this set of types in this > way? Is there some other more generic way of handling this case? > > ~Robert Widmann > > 2016/06/28 23:17、Riley Testut via swift-evolution <[email protected]> > のメッセージ: > >> Hello all, >> >> If you’ve been (attempting) protocol-oriented development in your own >> projects, I’m sure you’ve come across a particular build error at one point: >> >>> Protocol ‘MyProtocol' can only be used as a generic constraint because it >>> has Self or associated type requirements >> >> To be frank, this restriction in the current Swift model sucks, a lot. In >> *many* cases, this prevents me from using protocols, and instead I have to >> fall back to using concrete types. >> >> Here are a couple examples of using protocols with collections that should >> work fine, but simply don’t: >> >> A Set of Types Conforming to Protocol >> >> protocol MyProtocol: Hashable {} >> >> let set = Set<MyProtocol>() // ERROR: Protocol ‘MyProtocol' can only be used >> as a generic constraint because it has Self or associated type requirements >> >> When declaring a Set, the generic type of the Set’s contents must conform to >> Hashable. Following this, it would appear that you should be able to declare >> a Set containing types conforming to a given protocol which in turn conforms >> to Hashable. Nope! This also means you can’t have a Set<Hashable> (so no >> type-erased Sets for you!). One potential workaround is to use a box type, >> but if exposing the set to a user, this is essentially a leaky abstraction. >> >> Finding a Protocol Type Instance in an Array >> >> protocol MyProtocol {} >> struct MyStruct: MyProtocol {} >> >> var array = [MyProtocol]() >> array.append(MyStruct()) >> >> let index = array.index(of: MyStruct()) // ERROR: Cannot invoke 'index' with >> an argument list of type '(of: MyStruct)' >> >> So, we can’t use Set as a collection for our protocol types, let’s use Array >> instead! Not so fast: because MyProtocol doesn’t conform to Equatable, we >> can’t use the Array.index(of:) function to find it. Easy fix though, just >> make MyProtocol conform to Equatable, right? >> >> protocol MyProtocol: Equatable {} >> struct MyStruct: MyProtocol {} >> >> var array = [MyProtocol]() // ERROR: Protocol ‘MyProtocol' can only be used >> as a generic constraint because it has Self or associated type requirements >> >> Nope! Now that it conforms to Equatable, it can no longer be used in Array’s >> type declaration. However, there is a (somewhat) workaround for this problem: >> >> protocol MyProtocol {} >> func ==(lhs: MyProtocol, rhs: MyProtocol) -> Bool { return true } >> >> struct MyStruct: MyProtocol {} >> >> var array = [MyProtocol]() >> array.append(MyStruct()) >> >> let index = array.index(where: { $0 == MyStruct() }) >> >> Basically, we can define the == function for MyProtocol, and then instead of >> using Array.index(of:), we use Array.index(where:) to manually compare each >> item to see if it matches, aka what Array.index(of:) would do for us >> normally if we simply could declare MyProtocol as conforming to equatable. >> >> TL;DR >> Swift really pushes the idea of protocol-oriented programming, and for the >> most part this works well. However, due to some underlying restrictions in >> the current Swift model, you can’t use protocols in all the same places you >> can use concrete types, which sucks. This is especially confusing for >> beginners who are trying to use protocols, but get frustrated when it >> doesn’t work where they want it to (and don’t understand why), so they fall >> back to using concrete types (usually implemented with class inheritance). >> For this reason, I think these restrictions need to be fixed ASAP, or else >> the Swift language is essentially pushing people away from protocol-oriented >> programming. >> >> Riley Testut >> >> _______________________________________________ >> 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
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
