The problem is that: protocol should not be a type, but it is a type sometime and not type sometime now.
for exam: P.Type not same as T.Type But you can declare a variable of type P. Protocol should be a contract only, no instances of it. Charles Srstka via swift-evolution <[email protected]>于2016年8月17日 周三14:11写道: > On Aug 17, 2016, at 12:35 AM, Slava Pestov <[email protected]> wrote: > > > > On Aug 16, 2016, at 10:16 PM, Charles Srstka <[email protected]> > wrote: > > On Aug 16, 2016, at 11:42 PM, Slava Pestov <[email protected]> wrote: > > > Argh, that’s particularly frustrating since in something like ‘func foo<T > : P>(t: T)’ or ‘func foo<S : Sequence>(s: S) where S.IteratorElement: P’, > you’re only ever getting instances anyway since the parameter is in the > input, so calling initializers or static functions isn’t something you can > even do (unless you call .dynamicType, at which point you *do* have a > concrete type at runtime thanks to the dynamic check). > > > Well, if you have ‘func foo<T : P>(t: T)’, then you can write > T.someStaticMember() to call static members — it’s true you also have an > instance ’t’, but you can also work directly with the type. But I suspect > this is not what you meant, because: > > > Agh, you’re right, I’d forgotten about that. It’s days like this that I > miss Objective-C’s “It just works” dynamism. ;-) > > > Objective-C doesn’t have an equivalent of associated types or > contravariant Self, but I understand your frustration, because Sequence and > Equatable are pervasive in Swift. > > > I was thinking of Equatable, which in Objective-C was just the -isEqual: > method on NSObject, which we usually just started with a dynamic type check > in the cases where that mattered. I’m sure performance on Swift’s version > is much better, but the ObjC way was refreshingly surprise-free. > > The other trouble is that it’s not just confusing; it can very easily get > in the way of your work even if you know exactly what’s going on, > necessitating kludges like AnyHashable just to do things like have a > dictionary that can take more than one key type (an example that’s > particularly irritating since the only method you care about, hashValue, is > just a plain old Int that doesn’t care about the Self requirement at all). > I know that a while ago I ended up using my own Equatable substitute with > an ObjC-style isEqual() method on some types, just because actually > implementing Equatable was throwing a huge spanner into the rest of the > design. > > > Yeah, AnyHashable is basically a hand-coded existential type. It would > also be possible to do something similar for Equatable, where an > AnyEquatable type could return false for two values with differing concrete > types, removing the need for an == with contra-variant Self parameters. > > > Also: changing something into a class when it otherwise didn’t need to be > one, so you can use an ObjectIdentifier as a dictionary key, because using > a protocol that conformed to Hashable was dropping an atom bomb on the > entire rest of the project. > > Generalized existentials eliminate the restriction and thus the hacks. On > the other hand, they add yet more complexity to the language, so designing > them correctly involves difficult tradeoffs. > > > Fair enough. I guess I’ll wait it out a bit and see what the team comes up > with. > > Well, the idea was to create an easier-to-implement alternative to > self-conforming protocols, which could be done if :== were expanded to one > function that uses ==, and another with the same body that uses :, because > I was under the impression that the compiler team did not want to implement > self-conforming protocols. > > > I think the underlying machinery would be the same. We only want to > compile the body of a generic function body, without any kind of cloning > like in C++ templates, producing a general uninstantiated runtime form. So > :== T requirements would effectively require self-conforming protocols > anyway, since your function will have to dynamically handle both cases. > > The implementation for self-conforming opaque protocols is not difficult, > because the value itself can already be of any size, so it’s really not a > problem to have an existential in there. In theory, someone could cook it > up in a week or so. > > For class protocols, I don’t know how to do it without an efficiency hit > unfortunately. > > Consider these two functions, taking a homogeneous and heterogeneous array > of a class-bound protocol type: > > protocol P : class {} > > func f<T : P>(array: [T]) {} // this takes an array of pointers to T, > because there’s only one witness table for all of them > func ff(array: [P]) {} // this takes an array of <T, witness table> pairs, > two pointers each, because each element can be a different concrete type > > What you’re saying is that f() should in fact allow both representations, > because you’ll be able to call f() with a value of type [P]. Right now, if > we know a generic parameter is class-constrained, we use a much more > efficient representation for values of that type, that is known to be fixed > size in the LLVM IR. We would have to give that up to allow > class-constrained existentials to self-conform, since now a > class-constrained parameter can be an existential with any number of > witness tables. > > There might be some trick for doing this efficiently, but I don’t know of > one yet. > > Of course, we can just say that class-constrained protocols never > self-conform, unless they’re @objc. That seems like a hell of an esoteric > restriction though (can you imagine trying to come up with a clear phrasing > for *that* diagnostic?) > > And if you’re wondering, the reason that @objc protocols self-conform in > Swift today, is because they their existentials don’t have *any* witness > tables — @objc protocol method bodies are found by looking inside the > instance itself. > > AnyObject is the other kind of protocol that self-conforms — you can use > it both as a generic constraint, and as a concrete type bound to a generic > parameter, and it ‘just works’, because again it doesn’t have a witness > table. > > > Ah… because of the static dispatch, mapping the protocol members to > address offsets which may vary from member to member, as opposed to @objc > protocols, which I’d guess are probably doing the old-school lookup by > selector name à la objc_msgSend(). Hmm. I’d still probably argue that it’s > worth it, because I get the impression that Apple prefers the use of > generic sequence and collections for parameters rather than hard-coding > arrays, and frankly, with the current behavior it is slightly difficult to > do that. I guess it’s up to the compiler team, though. > > I will say that this has been an interesting discussion. Thanks for > offering your knowledge and insight. > > Charles > > _______________________________________________ > 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
