> Am 16.05.2016 um 21:29 schrieb Thorsten Seitz via swift-evolution 
> <swift-evolution@swift.org>:
> 
> 
>>> Am 15.05.2016 um 10:57 schrieb Adrian Zubarev via swift-evolution 
>>> <swift-evolution@swift.org>:
>>> 
>>> I think an important point is that `all<>` should NOT be restricted to 
>>> having only one reference or value type!
>> 
>> This is a little problematic and I’m not a compiler expert so from my 
>> perspective I could allow that but in a different way you see it (I’ll 
>> explain below).
>> 
>>> Ceylon does not have any restrictions like that. You can form the type 
>>> intersection of String and Integer for example, which are both classes in 
>>> Ceylon and because Ceylon like Swift only knows single inheritance between 
>>> classes, the result is simply `Nothing` (the bottom type which has no 
>>> elements). So there is no need to forbid this explicitly, because the types 
>>> work out just fine.
>> 
>> If I remember correctly someone said that `Ceylon` does use `all` and `any` 
>> for its Optional?! We can’t to do this in Swift as far as I know our 
>> playground.
>> 
>> We don’t have `Nothing` in Swift. The counterpart would be `Optional` but 
>> such a type is made explicit by `?` symbol like `Type? == Optional<Type>` 
>> and the only equivalent to `Nothing` would be `nil`.
>> 
> `Nothing` is the bottom type, i.e. the intersection of all types. It has no 
> members.
> `Nothing` has nothing to do with optionals. Optionals in Ceylon are type 
> unions with the type `Null` which has a single member called `null` (= 
> Swift’s nil).
> 
> Maybe this proposal should start with forbidding creating `All<>` expressions 
> which would evaluate to `Nothing` and a later proposal could introduce the 
> bottom type.
> 
>> That been said, if `All<>` would always intersect (what I haven’t proposed 
>> here at all) we can’t replace `protocol<>` with `All<>` because if we look 
>> at two distinct protocols `A` and `B` and try to merge them into a type 
>> `All<A, B>` would resolve in `implicit nil` where the old fashion way is not 
>> `protocol<A, B>`.
>> 
> I don’t know from where you got `implicit nil`. Seems I was a bit unclear :-)
> All<A, B> is the intersection type of A and B, i.e. a type which conforms to 
> A *and* B.
> Only for cases where A and B are *classes* which do *not* share an 
> inheritance relation the result of All<A, B> is `Nothing` (the empty bottom 
> type). This is a special case. The reason is that because of single 
> inheritance it is impossible to define a subtype of two different class 
> hierarchies.
> If A and B are structs the result of All<A, B> is `Nothing` as well, because 
> structs are not subtypeable at all. Note that All<StructA, StructA> will just 
> be StructA, though.
> If at least one of A and B is a protocol it is always possible to define a 
> type that conforms to A and B.
> 
>> By the way, really an `implicit nil`? This is not a great idea if you ask 
>> me. 
>> 
>> You may have a look at this document: 
>> https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md
>> 
>> `All<String, Int> == implicit nil` (your way) while it probably `All<String, 
>> Int>? == nil` would serve your wished behavior, but again I wasn’t proposing 
>> on solving this issue here. I’d like to solve this problem 
>> https://openradar.appspot.com/20990743 and open the door for `AnyStruct`, 
>> `AnyEnum`, `AnyValue` (maybe `AnyTuple` someday). This is what your hint for 
>> `Any<>` combined with my `All<>` might create.
>> 
>> If we allow multiple reference and value types for `All<>` this will only 
>> work with subtypeable types, because as I already described above 
>> `All<StructA, StructB>` can’t be merged.
>> 
> Yes, as long as subtyping structs is not possible in Swift All<StructA, 
> StructB> would be `Nothing` (again: this is not the type of `nil`).
> 
>> A scenario that will work might look like this:
>> 
>> class A {}     class B: A {}     class C: B {}
>> 
>> `All<B, C, A>` from the given types and my understanding the compile could 
>> and should infer `C` from here (not `B` compared to your example below).
>> 
> 
> Oops, sorry, you are right. I again made the error of confusing intersection 
> types (all<>) with union types (any<>). Grrr. I’m used to the type operators, 
> that’s my only excuse…
> 
>> To sum up a little we would have these facts:
>> 
>> - for subtypeable types the compile will search the highest type from the 
>> inheritance path and ignore all other lower base types (for `All<A, B>` the 
>> compile would infer `B == All<B> == All<B, A>`)
>> 
> With `highest` you mean `most specialized`, right? (for me that’s the lowest 
> type :-)
> 
>> - the oder of types should not matter because of the previous fact
>> 
> Exactly.
> 
>> That been said do we still need the whole inheritance branch inside of 
>> `All<>`? I don’t think so.
>> 
> Right, the whole branch is definitely not needed.
> 
>> Furthermore if we definitely should ignore order of `Types` inside the angle 
>> brackets like `All<A, B> == All<B, A>`, because it makes sense from the 
>> context of creating a `Type` that is constrained to `A` AND `B` where AND is 
>> commutative. I didn’t thought of at first glance, but thanks to your 
>> examples it’s clear to me know.
>> 
> Yes, `all<>` should be commutative.
> 
>> ———
>> 
>> If one would want to store or pass `A` from `class A: ClassB, ProtocolC` in 
>> some generic context and we don’t allow a second reference for `All<>` the 
>> following sample won’t work (generalized `class` is assumed):
>> 
>> `func <T: class>(value: All<T, ClassB, ProtocolC>)` but you can workaround 
>> here `func <T: ClassB>(value: All<T, ProtocolC>)` which can already be done 
>> `func <T: ClassB where T: ProtocolC>(value: T)`
>> 
>> The only problem that rises up here is that we can’t store that value inside 
>> a non-generic `Type` with both distinct `ClassB` and `ProtocolC` constraints 
>> merged together. As you might guess `ProtocolC` is applied onto `A` but not 
>> on `B` where `All<ClassB, ProtocolC>` will create a whole new type for us 
>> (https://openradar.appspot.com/20990743).
>> 
>>> Furthermore you can form type intersections between reference types which 
>>> inherit from each other. The resulting intersection type is valid and is 
>>> just equal to the more specific type. And of course you can form type 
>>> intersections of a reference or value type with itself (i.e. all<SomeClass, 
>>> SomeClass>).
>> 
>>> Why should that be useful you may ask?
>>> 
>>> This generality is important when using intersection types with generics: 
>>> let’s consider the type of a function forming the intersection of two sets 
>>> with different element types:
>>> 
>>> func union<T, U>(a: Set<T>, b: Set<U>) -> Set<all<T, U>> { … }

The text is correctly talking about intersection and the types are correct for 
forming the intersection, but of course the function should be called 
`intersection` as well!
This applies to its usage in the examples below...

Maybe we should use `union<>` and `intersection<>` :-)

-Thorsten 


>>> 
>>> 
>>> Requiring all<T,U> to have at most one reference or value type (which must 
>>> be at first position) would impose some unnecessary restrictions:
>>> 
>>> Given the following:
>>> 
>>> protocol Named {}
>>> class Person : Named {}
>>> class Employee : Person {}
>>> 
>>> let people: Set<Person>
>>> let otherPeople: Set<Person>
>>> let employees: Set<Employee>
>>> let namedOnes: Set<Named>
>>> 
>>> // unnecessary restriction:
>>> let x1 = union(namedOnes, people)  // not allowed, because result type 
>>> contains all<Named, Person> 
>> 
>>> // the restriction would require us to write:
>>> let x2 = union(people, namedOnes)  // ok, result type would be 
>>> Set<all<Person, Named>> which would be simplified by the compiler to 
>>> Set<Named>
> 
> Correction: Set<all<Person, Named>> = Set<Person & Named> = Set<Person>
> 
>>> (Ceylon does this!)
>> 
>>> // unnecessary restriction:
>>> let x3 = union(people, employees)   // not allowed, because result type 
>>> would contain all<Person, Employee> with two reference types
>> 
>>> // unnecessary restriction
>>> let x4 = union(people, otherPeople)   // not allowed, because result type 
>>> contains all<Person, Person> with two reference types
>> 
>>> 
>>> IMO these should all be allowed (and are possible in Ceylon). 
>>> The result type of x1 would be Set<all<Named, Person>> which would be 
>>> simplified by the compiler to Set<Named>.
> 
> Correction: Set<Person>
> 
>>> The result type of x2 would be Set<all<Person, Named>> which would be 
>>> simplified by the compiler to Set<Named>.
> 
> Correction: again Set<Person>
> 
>>> The result type of x3 would be Set<all<Person, Employee>> which would be 
>>> simplified by the compiler to Set<Employee>.
>>> The result type of x4 would be Set<all<Person, Person>> which would be 
>>> simplified by the compiler to Set<Person>.
> 
> These two are correct, at least…
> 
> Sorry again for the confusion!
> 
> -Thorsten
> 
> 
>>> 
>>> -Thorsten
>> 
>> Pleas rethink your example here, `Intersection<>` might be a proposal of its 
>> own (there are some problems with `Nothing` I described above).
>> 
>> ——— 
>> 
>> `Any<>` will pick only one type from its angle brackets. The types must be 
>> distinct to each other, but `Any<>` is a whole other proposal which has its 
>> own problems like:
>> 
>> protocol A {}    protocol B {}     class C: A, B {}
>> 
>> func foo(value: Any<A, B>) {
>>      // if else if won’t handle `value` correctly if it’s `C`
>> }
>> 
>> Is such a thing intended? I guess `Any<>` should just proceed when the first 
>> match is found at compile time and it’s up to the developer to handle 
>> `value` correctly.
>> 
>> In different thread I just answered my vision for `All<>` and future `Any<>`:
>> 
>> There are two future directions in my proposal: 
>>        (1) `Any<>` which takes only one type from the angle brackets: 
>> `Any<String, Int>` or `String | Int`
>>        (2) if we already have a generalized `class` keyword, so why we don’t 
>> get `struct` and `enum` as well?
>> 
>> With this we can create a typealias for `AnyValue` like this (at least for 
>> generalized extendable types): 
>>        `typealias AnyStruct = All<struct>`
>>        `typealias AnyEnum = All<enum>`
>>        `typealias AnyValue = Any<All<struct>, All<enum>>`
>>        `typealias AnyValue = AnyStruct | AnyEnum`
>> 
>> -- 
>> Adrian Zubarev
>> Sent with Airmail
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to