> On Jun 16, 2016, at 3:29 PM, Thorsten Seitz via swift-evolution
> <[email protected]> wrote:
>
>
>
>> Am 13.06.2016 um 04:04 schrieb Dave Abrahams <[email protected]>:
>>
>>
>> on Fri Jun 10 2016, Thorsten Seitz <tseitz42-AT-icloud.com> wrote:
>>
>>>> Am 09.06.2016 um 19:50 schrieb Thorsten Seitz via swift-evolution
>>>> <[email protected]>:
>>>>
>>>>
>>>>> Am 09.06.2016 um 18:49 schrieb Dave Abrahams via swift-evolution
>>>>> <[email protected]>:
>>>
>>>>>
>>>>> on Wed Jun 08 2016, Jordan Rose <[email protected]> wrote:
>>>>>
>>>>>>> On Jun 8, 2016, at 13:16, Dave Abrahams via swift-evolution
>>>>>>> <[email protected]> wrote:
>>>>>>>
>>>>>>>
>>>>>>> on Wed Jun 08 2016, Thorsten Seitz
>>>>>>
>>>>>>> <[email protected]
>>>>>>> <mailto:[email protected]>>
>>>>>>> wrote:
>>>>>>>
>>>>>>>> Ah, thanks, I forgot! I still consider this a bug, though (will have
>>>>>>>> to read up again what the reasons are for that behavior).
>>>>>>>
>>>>>>> Yes, but in the case of the issue we're discussing, the choices are:
>>>>>>>
>>>>>>> 1. Omit from the existential's API any protocol requirements that depend
>>>>>>> on Self or associated types, in which case it *can't* conform to
>>>>>>> itself because it doesn't fulfill the requirements.
>>>>>>>
>>>>>>> 2. Erase type relationships and trap at runtime when they don't line up.
>>>>>>>
>>>>>>> Matthew has been arguing against #2, but you can't “fix the bug” without
>>>>>>> it.
>>>>>>
>>>>>> #1 has been my preference for a while as well, at least as a starting
>>>>>> point.
>>>>>
>>>>> I should point out that with the resyntaxing of existentials to
>>>>> Any<Protocols...>, the idea that Collection's existential doesn't
>>>>> conform to Collection becomes far less absurd than it was, so maybe this
>>>>> is not so bad.
>>>>
>>>> I think the problem is more that Any<Collection> does not conform to
>>>> a specific value for a type parameter T: Collection
>>>>
>>>> What I mean by this is that `Collection` denotes a type family, a
>>>> generic parameter `T: Collection` denotes a specific (though
>>>> unknown) member of that type family and `Any<Collection>` denotes
>>>> the type family again, so there is really no point in writing
>>>> Any<Collection> IMO.
>>>> The type family cannot conform to T because T is just one fixed member of
>>>> it.
>>>> It conforms to itself, though, as I can write
>>>> let c1: Any<Collection> = …
>>>> let c2: Any<Collection> = c1
>>>>
>>>> That’s why I think that we could just drop Any<Collection> and simply
>>>> write Collection.
>>>
>>> Let me expand that a bit:
>>>
>>> Actually all this talk about existentials vs. generics or protocols
>>> vs. classes has had me confused somewhat and I think there are still
>>> some misconceptions present on this list sometimes, so I’ll try to
>>> clear them up:
>>
>> There are several objectively incorrect statements here, and several
>> others with which I disagree. I was hoping someone else would write
>> this for me, but since the post has such a tone of authority I feel I
>> must respond.
>
> You are right, the tone of my post was not appropriate, for which I want to
> apologize sincerely.
>
> I still believe my statements to be valid, though, and will respond to your
> arguments inline. Please don't get me wrong, I'm not trying to have an
> argument for the argument's sake. All I want is to contribute maybe a tiny
> bit to make Swift even better than it already is, by sharing ideas and
> thoughts not only from me but from the designs of other perhaps more obscure
> programming languages which I happen to have stumbled upon in the past (often
> with much delight).
>
>>
>>> (1) misconception: protocols with associated types are somehow very
>>> different from generics
>>>
>>> I don’t think they are and I will explain why. The only difference is
>>> the way the type parameters are bound: generics use explicit parameter
>>> lists whereas protocols use inheritance. That has some advantages
>>> (think long parameter lists of generics) and some disadvantages.
>>> These ways are dual in a notation sense: generic types have to have
>>> all parameters bound whereas protocols cannot bind any of them.
>>> The „existential“ notation `Any<>` being discussed on this list is
>>> nothing more than adding the ability to protocols to bind the
>>> parameters to be used just like Java’s wildcards are adding the
>>> opposite feature to generics, namely not having to bind all
>>> parameters.
>>
>> Protocols and generics fulfill completely different roles in Swift, and
>> so, **especially in a language design context like the one we're in
>> here**, must be thought of differently. The former are an abstraction
>> mechanism for APIs, and the latter a mechanism for generalizing
>> implementations.
>
> That's not what I was talking about. Of course, protocols are a mechanism for
> deriving types from each other whereas generics are a way to parameterize
> types. My point was that Swift's other way to parameterize types, namely by
> associated types, is very similar to generics with wildcards when looking a
> the existentials of such protocols. In addition I was talking about generics
> in general, not just about generics in Swift which restricts them to
> implementations and does not support wildcards.
> Other languages like Java offer generics for interfaces as well and support
> wildcards (adding generic types parameters to protocols in Swift is currently
> discussed on the mailing list as well).
> FWIW my arguments were not about whether we should have wildcards in Swift or
> not, but simply to relate one parametrization feature (associated types) to a
> more well known parametrization feature (generics with wildcards) in order to
> understand them better.
>
>> The only place you could argue that they intersect is
>> in generic non-final classes, because a class fills the dual role of
>> abstraction and implementation mechanism (and some might say that's a
>> weakness). But even accounting for generic classes, protocols with
>> associated types are very different from generics. Two utterly
>> different types (an enum and a struct, for example) can conform to any
>> given protocol P, but generic types always share a common basis
>> implementation.
>
> The latter is not the case for generic interfaces in Java, for example, so it
> is just an artificial restriction present in Swift.
>
>> There is no way to produce distinct instances of a
>> generic type with all its type parameters bound,
>
> That is true in Swift (except for generic classes) due to the restriction
> just mentioned.
>
>> but for any protocol P
>> I can make infinitely many instances of P with P.AssociatedType == Int.
>
>
> This likewise applies to generic interfaces and for generic types in general
> if taking inheritance into account - just like you do here for protocols.
>
>> Back to the my original point: while protocols and generic types have
>> some similarities, the idea that they are fundamentally the same thing
>> (I know you didn't say *exactly* that, but I think it will be read that
>> way) would be wrong and a very unproductive way to approach language
>> evolution.
>
> I said that protocols *with associated types* are much like generics *with
> wildcards* and tried to show why.
>
>>
>>> Essentially `Any<Collection>` in Swift is just the same as
>>> `Collection<?>` in Java (assuming for comparability’s sake that
>>> Swift’s Collection had no additional associated types; otherwise I
>>> would just have to introduce a Collection<Element, Index> in Java).
>>
>> I don't see how you can use an example that requires *assuming away*
>> assoociated types to justify an argument that protocols *with associated
>> types* are the same as generics.
>
> Note, that I said *additional* associated types, i.e. in addition to
> .Element, even giving an example how the Java interface had to be extended by
> a type parameter `Index` if this assumption was not applied (still
> simplifying because Generator would have been more correct which would have
> to be added as type parameter in addition to `Index`).
>
> So, in essence the comparison is between the following (I'm using Foo now
> instead of Collection to avoid the differences mentioned. Note that this has
> no impact on the argument at all):
>
> protocol Foo {
> associatedtype T
> ...
> }
>
> interface Foo<T> {
> ...
> }
>
> My argument is that existentials of protocols with associated types are just
> like generic types with wildcards, i.e. `Any<Foo>` in Swift is just the same
> as `Foo<?>` in Java.
> Likewise `Any<Foo where .T: Number>` is just the same as `Foo<? extends
> Number>` in Java. For me that was an insight I wanted to share.
The like-ness applies only to a subset of the java type system, and this is the
area that will drastically change within the next 2 years.
>>>
>>> And just like Collection<?> does not conform to a type parameter `T
>>> extends Collection<?>` because Collection<?> is the type `forall
>>> E. Collection<E>` whereas `T extends Collection<?>` is the type
>>> `T. Collection<T>` for a given T.
>>>
>>> In essence protocols with associated types are like generics with
>>> wildcards.
>>
>> It is true that generics with wildcards in Java *are* (not just “like”)
>> existential types but I don't agree with the statement above. Because
>> Java tries to create an “everything is a class” world,
Never did, never will...
>> generic classes
>> with bound type parameters end up playing the role of existential type.
>> But protocols in Swift are not, fundamentally, just existential types,
>> and the resyntaxing of ProtocolName to Any<ProtocolName> for use in type
>> context is a huge leap forward in making that distinction clear... when
>> that's done (unless we leave Array<ProtocolName> around as a synonym for
>> Array<Any<ProtocolName>>—I really hope we won't!) protocols indeed
Hmmm starting to see the ugly Any<> burgeoning all over swift soon... :(
>> *won't* be types at all, existential or otherwise.
>
> I fully agree that protocols are not types, their existentials are. But I
> haven't seen yet what we really *gain* from making that distinction explicit
> (except an ugly type syntax :-).
> And like I already wrote in this or another thread we would have to apply the
> same logic to non-final classes, which are existentials, too.
>
>
>>
>>> Coming back to the questions whether (a) allowing existentials to be
>>> used as types is useful
>>
>> That's the only use existentials have. They *are* types. Of course
>> they're useful, and I don't think anyone was arguing otherwise.
>
> I'm pretty sure that there was a discussion about whether being able to write
> something like Any<Collection> is useful. My wording was certainly imprecise,
> though, and didn't make sense as written. I should have said something like
> "whether adding the ability to use existential types of protocols with
> unbound associated types is useful".
>
>>
>>> and (b) whether sacrificing type safety would somehow be necessary for
>>> that, I think we can safely answer (a) yes, it *is* useful to be able
>>> to use existentials like Any<Collection> as types, because wildcards
>>> are quite often needed and very useful in Java (they haven’t been
>>> added without a reason) (b) no, sacrificing type safety does not make
>>> sense, as the experience with Java’s wildcards shows that this is not
>>> needed.
>>
>> I would call this “interesting information,” but hardly conclusive.
>> Java's generics are almost exactly the same thing as Objective-C
>> lightweight generics, which are less capable and less expressive in
>> many ways than Swift's generics.
>
> I agree that Java does not have something like `Self` or associated types
> (which are really useful for not having to bind all type parameters
> explicitly, especially when binding type parameters to other generics which
> makes for long type parameter lists in Java where I have to repeat everything
> over and over again), but do you mean something else here?
> Especially in the context of sacrificing type safety?
>
>>
>>> Especially if something like path dependent types is used like
>>> proposed and some notation to open an existential’s type is added,
>>> which is both something that Java does not have.
>>>
>>> (2) misconception: POP is different from OOP
>>>
>>> It is not. Protocols are just interfaces using subtyping like OOP has
>>> always done. They just use associated types instead of explicit type
>>> parameters for generics (see above).
>>
>> They are not the same thing at all (see above ;->). To add to the list
>> above, protocols can express fundamental relationships—like Self
>> requirements—that OOP simply can't handle.
>
> Eiffel has something like Self, it is called anchoring and allows binding the
> type of a variable to that of another one or self (which is called `Current`
> in Eiffel). And Eiffel does model everything with classes which may be
> abstract and allow for real multiple inheritance with abilities to resolve
> all conflicts including those concerning state (which is what other languages
> introduce interfaces for to avoid conflicts concerning state while still
> failing to solve *semantic* conflicts with the same diamond pattern).
> No protocols or interfaces needed. Why do you say this is not OOP? The book
> which describes Eiffel is called "Object-Oriented Software Construction" (and
> is now about 20 years old).
>
>
>> There's a reason Java can't
>> express Comparable without losing static type-safety.
>
> You are certainly right that Java is not the best language out there
> especially when talking about type systems (I often enough rant about it :-)
> but I'm not sure what you mean here. Java's Comparable<T> seems quite
> typesafe to me. Or do you mean that one could write `class A implements
> Comparable<B>` by mistake? That's certainly a weak point but doesn't
> compromise type safety, does it?
> Ceylon has an elegant solution for that without using Self types:
>
> interface Comparable<in Other> of Other given Other satisfies
> Comparable<Other> {...}
>
> Note the variance annotation (which Swift currently has not) and the `of`
> which ensures that the only subtype of Comparable<T> is T. This is a nice
> feature that I haven't seen often in programming languages (only Cecil comes
> to mind IIRC) and which is used for enumerations as well in Ceylon. In Swift
> I cannot do this but can use Self which solves this problem differently,
> albeit with some drawbacks compared to Ceylon's solution (having to redefine
> the compare method in all subtypes, which has lead to lengthy discussion
> threads about Self, StaticSelf, #Self etc.).
>
>> Finally, in a
>> language with first-class value types, taking a protocol-oriented
>> approach to abstraction leads to *fundamentally* different designs from
>> what you get using OOP.
>
> Eiffel has expanded types which are value types with copy semantics quite
> like structs in Swift. These expanded types are pretty much integrated into
> Eiffel's class-only type system. Just define a class as `expanded` and you
> are done. Eiffel seems to have no need to introduce interfaces or protocols
> to the language to support value types.
> You can even derive from expanded classes which is currently not possible in
> Swift but has already been discussed several times on this mailing list.
> Polymorphic usage is only possible for non expanded super types, which means
> as far as I understood that a reference is used in that case. Variables with
> an expanded type do not use refences and therefore may not be used
> polymorphically in Eiffel.
> This should be similar in Swift, at least as far as I did understand it. The
> question whether variables with a value type can be used polymorphically
> currently does not arise in Swift as structs cannot inherit from each other
> (yet?).
>
>>
>>> The more important distinction of Swift is emphasizing value types and
>>> making mutation safely available by enforcing copy semantics for value
>>> types.
>>
>> We don't, in fact, enforce copy semantics for value types. That's
>> something I'd like to change. But regardless, value types would be a
>> *lot* less useful if they couldn't conform to protocols, and so they
>> would be a lot less used. Heck, before we got protocol extensions in
>> Swift 2, there was basically *no way* to share implementation among
>> value types. So you can't take protocols out of the picture without
>> making value types, and the argument for value semantics, far weaker.
Value types are coming to the jvm without protocols.
> Why? Like I said, Eiffel *has* value types without needing protocols. They
> just have a unified mechanism built around classes.
>
>
>>
>>> But protocols are not really different from interfaces in Java.
>>> I would have preferred a unified model using just classes with real
>>> multiple inheritance like Eiffel has and value types just being a part
>>> of that similar to Eiffel’s `expanded` classes. But that ship has
>>> probably sailed a long time ago :-/ So be it. But at least there
>>> should be no reasons for POP vs OOP wars ;-) (I’d like to add that I
>>> liked Dave’s talks at last WWDC very much, it’s just that I don’t
>>> think that POP is something new or different.)
>>
>> Protocol-oriented programming is about the synergy of features and ideas
>> most of which not *individually* new, but that together create a new
>> world of possibilities. I've already discussed the synergy of protocols
>> and first-class value semantics.
>
> Again, I think that Eiffel demonstrates that protocols are not needed for
> first-class value semantics.
So does the clr today and soon the jvm.
>
>
>> There's also the fact that in
>> protocols we have one construct with which to express dynamic
>> polymorphism (existentials) and static polymorphism (generic
>> constraints), both of which have important roles to play but that I
>> maintain are very different indeed.
>
> I don't argue with the fact that protocols can be used for both of these
> roles (existentials and constraints) and that these roles are something
> different. But I didn't say anything like that, at least not intentionally.
>
>
>> One result is that you can “start
>> with a protocol” as your abstraction mechanism and know that you're not
>> going to design yourself into a corner where it becomes impossibly
>> awkward to express what you need.
>
> Not sure what problems you are hinting at here specifically? Is it the single
> inheritance restriction most languages impose on classes? In that case I
> agree with you that that is a problem. I would not agree with interfaces
> being the only or even best solution, though, because I would prefer classes
> with real support for multiple inheritance like Eiffel shows is possible
> (especially as interfaces do not solve all problems with MI).
>
>
>> Finally—and I'm certain this *is*
>> new—in protocol extensions we have a means to express both post-hoc
>> conformance and generic functions that is much more accessible to users
>> than in any previous language, to the point where generic programming
>> can become a natural part of everyday work.
>
> Protocol extensions are a great feature that I was very very happy to see
> after having used extensions in Smalltalk for many years and missing them in
> Java. Especially being able to use post-hoc conformance is a really nice
> feature!
>
> Please don't get me wrong, I think Swift is a fantastic language and I love
> it.
> I'm not arguing for removal of protocols in Swift or something like that.
> That ship has sailed. But I don't think that classes should be second class
> citizens in Swift, like several posts on this mailing list implied, e.g. in
> the discussion about abstract classes.
>
I don't think the core team views them as second-class considering the
restructuring that went in jn Foundation, i.e pairing Data with NSData ...
val+ref is the arghment Dave was making a few weeks ago in the discussion
around PureValue
> Best regards
>
> -Thorsten
> _______________________________________________
> 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