[swift-evolution] Enhanced existential types proposal discussion

Adrian Zubarev adrian.zubarev at devandartist.com
Wed May 18 15:57:26 CDT 2016

So without any initial constraints how would one use this generic function??

extension UIButton: ProtocolA {}

let button = UIButton()
let shadowedButton: ProtocolA = UIButton()

// creates a set of a least one element if the generic type could be inferred
func unionIfPossible<T, U>(_ a: T, _ b: U) -> Set<Any<T, U>>? { /* merge somehow if possible */ }

You would not be able to form Any<T, U> here because T and U are generic arguments unknown.  We don’t accept those, only `class`, specific classes, and specific protocols (and recursively, other Any).

Why would Any<…> does not work with the generic system here? To me it makes no sense, I as a developer would assume I can use a generic Type anywhere a type can be used (protocols and their associated types are a special case).

I would assume that:

func foo<T: UIView>(value: Any<T, SomeProtocol>)

should be equal to (without the need of generics):

func foo(value: Any<UIView, SomeProtocol>)

// this should be valid because the compiler will assume Any<UIView, ProtocolA> where T == UIView and U == ProtocolA
let merged_1: Set<Any<UIView, ProtocolA>> = unionIfPossible( /* UIView subtype */ button, /* ProtocolA */ shadowedButton) 

// this won’t be possible because of the restriction
let merged_2: Set<Any<UIView, ProtocolA>> = unionIfPossible(shadowedButton, button) 

Any<UIView, ProtocolA> != Any<ProtocolA, UIView> isn’t right. Sure it may feel right for readability but the types should be equal.

"Can be any class type that is a UIView or a subclass of UIView, that also conforms to ProtocolA.“ == "Type that conforms to ProtocolA and that is a UIView or a subclass of UIView.“

This is also a nesting problem where you will be forced to choose the right place inside the angle brackets where to add a nested `Any<…>`.

class A: ClassB, ProtocolA {}

Any<A, Any<ClassB, ProtocolA>> == A != Any<Any<ClassB, ProtocolA>, A> == Any<ClassB, ProtocolA, A> which should be reorder by the compiler and inferred as A

`Any<Any<ClassB, ProtocolA>, A>` is not allowed because if a class is provided it must come first.

`Any<ClassB, ProtocolA, A>` is not allowed because it contains more than one class.
Not true, take a look at the nested section of the proposal again.

We discussed that this is valid:

// Allowed, but pointless.
// Identical to Any<ProtocolA, ProtocolB>
let b : Any<Any<ProtocolA, ProtocolB>>

This implies that also this would be valid:

Any<Any<ClassA, ProtocolA>> inferred as Any<ClassA, ProtocolA>

There is another example:

// Can be any type that is a UITableView conforming to ProtocolA.
// UITableView is the most specific class, and it is a subclass of the other
// two classes.
let a : Any<UIScrollView, Any<UITableView, Any<UIView, ProtocolA>>>

Which followed by the mentioned rule can als be:

Any<UIScrollView, UITableView, Any<UIView, ProtocolA>> or
Any<UIScrollView, UITableView, UIView, ProtocolA>

This would force us to allow multiple classes inside Any<…> if there is a inheritance relationship between them.

And because this is a inheritance relationship it can be simplified to:

Any<UITableView, ProtocolA> which is valid. 

And by the way since the order in your proposal would matter, this example won’t work at all, because its not:

Any<UITableView, Any<UIScrollView, Any<UIView, ProtocolA>>> 

In my proposal I explicitly banned multiple reference types and inheritance branches like this. I would need to simplify that type to Any<UITableView, ProtocolA> by myself.
Ingeneral this is a good idea, but it makes nesting (with typealiases) almost impossible, when there are some relationship like in the above example.

Adrian Zubarev
Sent with Airmail
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160518/dad5bc89/attachment.html>

More information about the swift-evolution mailing list