SE-0335: Introduce existential `any`

Review Summary

  • What is your evaluation of the proposal?

+1 to the feature, although I have some significant disagreements with the proposal text.

  • Is the problem being addressed significant enough to warrant a change to Swift?

Definitely. Generics are too difficult for new developers, and this syntax change helps clarify one aspect of it. I believe we need to radically rethink the entire language model around generics.

  • Does this proposal fit well with the feel and direction of Swift?

I believe it does.

  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Swift's generics system is quite unlike other languages I've used, so I can't comment.

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I've thought about this issue a great deal, and posted about this problem many times in the past. Unfortunately, I wasn't able to participate in the pitch thread; it was open for only 3 weeks (which, when you consider the scope of this change, is astounding), at the end of the year when everybody is busy with their own projects.

There are a lot of proposals floating around right now, so clearly the team at Apple is also trying to get their projects done or meet some milestones before the new year. The rest of us are, too! But we don't generally have entire work-days to devote to swift-evolution!

I've mentioned it several times in the past, and I'll continue mentioning it: we don't give nearly enough time to analyse proposals of this scale, and I find the lack of consideration for what is traditionally a busy time of year to be disrespectful to the entire Swift community.

At least in this case, one person who (at least in their opinion) has something to contribute, was not able to participate in earlier phases because of the rushed schedule. I urge the core team to change this part of the process. I think the community would be better served taking time to devise a thorough plan for the future of generics, rather than hastily pushing through one-off proposals.


The Proposal

Again, limited time for a discussion of this deep and intricate topic, so I'm just going to speed through the proposal mention the parts I disagree with.

Existential types in Swift have significant limitations and performance implications. Some of their limitations are missing language features, but many are fundamental to their type-erasing semantics.

Some of their limitations (the biggest limitations, in fact) are due to the compiler being stubbornly literal about how it interprets code using existentials. Most of these issues could be cleared up by teaching the language model that, very very very often, value-level and type-level abstraction are one and the same thing.

Basically the only operation which splits the two is assignment. For quite literally everything else (including mutating methods), it's not possible to change the value's type.

func useExistential(p: P) {
  generic(p: p, value: ???) // what type of value would P.A be??
}

There is actually an obvious answer to this - it is a value whose type may be coerced to the associated type of the value currently in p.

Syntactically, the cost of using one is hidden, and the similar spelling to generic constraints has caused many programmers to confuse existential types with generics. In reality, the need for the dynamism they provided is relatively rare compared to the need for generics, but the language makes existential types too easy to reach for, especially by mistake.

There is a deeper question here - why does the language pretend that this dynamism exists, even in contexts where it quite clearly does not?

There is no dynamism in the useExistential function above. p never changes its type. The optimiser knows this (which is why the mentioned costs are actually not as bad as one might expect), but the language model does not. Existentials are just artificially handicapped because our model of generics in the language is focussed on being explicit about differences which don't exist 90+% of the time.

any Any and any AnyObject are redundant. Any and AnyObject are already special types in the language, and their existence isnโ€™t nearly as harmful as existential types for regular protocols because the type-erasing semantics is already explicit in the name.

I find it strange that Any and AnyObject are the only existential types which do not require the any keyword. It seems more cohesive to spell Any as any, and AnyObject as any Object.

I see the argument about churn, and I'm not convinced. We could still accept Any and AnyObject during a transition period, and IMO having these existentials (probably the most commonly-used existentials) stick with the legacy syntax creates an even more complex and confusing language model. Wasn't this proposal all about making things simpler and clearer for developers? Consistency would help.

There's already going to be a lot of churn. Why is it not worth changing these, but it is worth changing every other existential across the entirety of all code written in Swift?

The existential metatype, i.e. P.Type , becomes any P.Type . The protocol metatype, i.e. P.Protocol , becomes (any P).Type . The protocol metatype value P.self becomes (any P).self

To be honest, I don't think anybody's going to remember this; what they're going to do is awkwardly fumble around with the syntax until the darn thing just compiles! And I'll be right there with them. The whole .Protocol, .Type and .self stuff just barely makes sense as it is, and this change makes the differences even more subtle - (any P).self vs any P.self vs (any P).Type vs any P.Type.

I actually think this part of the proposal is a regression compared to what we have today.

Extending existential types

Please no. Can we remove this "Future Direction"? It's not necessary, and it's far from uncontroversial.

See Lifting the "Self or associated type" constraint on existentials - #138 by Karl for more information.

2 Likes