[swift-evolution] [swift-evolution-announce] [Review] SE-0089: Replace protocol<P1, P2> syntax with Any<P1, P2>

Tyler Cloutier cloutiertyler at aol.com
Tue May 24 14:25:49 CDT 2016

> On May 24, 2016, at 12:07 PM, Joe Groff via swift-evolution <swift-evolution at swift.org> wrote:
> 'Any' is definitely a better name, but I think this is still syntax only a compiler can love. If we're going to repaint this bikeshed, I think we should also consider as an alternative some form of infix syntax for composing constraints. Rust uses `P1 + P2`, and various C++ proposals have suggested `P1 && P2`. Some pros(+) and cons(-) I can see with this approach:
> + Infix notation works not only in type position, but constraint position as well, providing a nicer way to express multiple type variable constraints:
> 	var x: P && Q
> 	func foo<T: P && Q, U>(x: T)
> + Infix notation feels subjectively lighter, being less nesty and angle-bracket-blinding. Compare the above with:
> 	var x: Any<P, Q>
> 	func foo<T: Any<P,Q>, U>(x: T)

Perhaps just a comma separated list like a type-inheritance-clause, using parenthesis for disambiguation?

var x: P, Q
func foo<(T: P, Q), U>

func foo<T: (P, Q), U>

> Particularly in the second declaration, I find the nested angle brackets and comma delimiters to be hard to visually parse.
> ± Like 'Any', an infix operator doesn't pass judgment on what kinds of constraint is being applied, so it naturally extends to expressing class-with-protocol constraints.
> - Infix notation doesn't provide an obvious place for generalized existentials to hang secondary constraints. The angle brackets for Any provide an enclosed syntactic space we can easily stuff a 'where' clause:
> 	func sum(_ collection: Any<Sequence where Element == Int>) -> Int { ... }
> (though this notation still feels heavy and awkward to me).
> - The bracketing of `Any` might let us address the curious case of protocol vs existential metatypes in a better way. Right now, the static metatype for a protocol type (the type of `P.self`) is spelled `P.Protocol`, and the dynamic metatype for any type conforming to the protocol (the erased type of `T.self` where T: P) is spelled `P.Type`. Unintuitively, when a protocol type is substituted into `T.Type` in a generic context, you get the static type `P.Protocol` rather than `P.Type`, for soundness reasons:
> 	func staticType<T>(of _: T) -> T.Type { return T.self }
> This substitution behavior could be made clearer if we moved a dynamic metatype's `.Type` into the Any brackets, so that `Any<P.Type>` would be the dynamic metatype of any type conforming to P, and `Any<P>.Type` would be the static metatype of the type `Any<P>`. Infix notation doesn't provide an opportunity to make this clarification.
> - A few people have also noted the similarity between Any<...> and normal generic types. This is potentially confusing today, but with enough magic language features from the future, Any *could* conceivably be made a library feature in the fullness of time:
> 	// Let's say 'protocol' constraints indicate second-order constraint variables:
> 	enum Any<Constraints: protocol> {
> 		// And we have GADTs:
> 		case value<T: Constraints>(T)
> 	}
> 	// And we have user-defined value subtyping:
> 	extension <Constraints: protocol, T: Constraints> T: Any<Constraints> { ... }
> -Joe
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160524/19ce58f0/attachment.html>

More information about the swift-evolution mailing list