# Confusing opening existentials syntax

From "Opening existentials" in the Generics Manifesto:

``````if let storedInE1 = e1 openas T { // T is the type of storedInE1, a copy of the value stored in e1
if let storedInE2 = e2 as? T {  // Does e2 have type T? If so, copy its value to storedInE2
if storedInE1 == storedInE2 { ... } // Okay: storedInT1 and storedInE2 are both of type T, which we know is Equatable
}
}
``````

What is the difference between `e1 openas T` and `e2 as? T`?
Or in pointfree notation: what is the difference between `openas` and `as?`/`as!`?

I believe whatâ€™s happening here is that the `openas` operation is creating some dynamic type T and once itâ€™s binded the valueâ€™s dynamic type to a local type T then you can just use the regular cast operation to see if the other value is T.

2 Likes

The `T` in `openas T` is declaring a new type `T`. It would be more clear to make the declaration of `T` explicit, e.g., `e1 openas<T> T`.

Doug

5 Likes

What about something like this, with an explicit type "placeholder" on the left of the assignment?

``````if let storedInE1: <T> = e1 {
//...
}
``````

I like the direction this is in. I would still like an explicit open operation:

``````if let storedInE1<T>: T = e1 openas T {}
``````

I suggested the following syntax in the opaque types manifesto:

4 Likes

Cool, now I also understand that part of the manifesto. And thank you @Karl for sharing the example. It makes more sense to me on how opening existentials could potentially work.

1 Like

Opening existentials is not really a conditional operation, so associating it with `if let` is probably confusing as strawman syntax. Something like Karl's syntax makes more sense to me.

My own preference would be that existentials automatically open, and that we have some sort of syntax for expressing types relative to existential `let` bindings. So you could say:

``````let objects: Collection = ...
let destination: Collection = ...

if let destination = objects as? type(of: objects) { ... }
``````
8 Likes

This is exactly what confused me. Let's fix in this in the manifesto and improve the comments

This now makes sense! Especially with Joe's clarification.

That would be cool, but it seems to only work well for comparing types which are exactly equal. If youâ€™re checking multiple associated types, it becomes quite verbose and would require some kind of flow-tracking to keep track of which constraints youâ€™ve tested for each existential:

``````let objects: Collection = ...
let destination: Collection = ...

if type(of: destination).Element == type(of: objects).Element {
// compiler needs to keep track of the above constraint
let sameContents = objects.elementsEqual(destination)
}
``````

It is quite nice and approachable, though. It helps avoid some of the â€śangle-bracket blindnessâ€ť.

If we borrowed Scalaâ€™s syntax for path-dependent types then we could say `destination.Element` and `objects.Element`. I think this is a good direction.

3 Likes