SE-0352 (second review): Implicitly Opened Existentials

Hi everyone. The second review of SE-0352: Implicitly Opened Existentials begins now and runs through May 18th, 2022. The first review thread is at:

This second revision of the proposal incorporates feedback from the first review about how result type erasure should account for future language evolution, such as same-type-constrained existentials as proposed and currently being reviewed in SE-0353, proposing that an explicit type annotation be required in cases where the existential result type would lose generic constraints because of expressivity limitations in the language.

Reviews are an important part of the Swift evolution process. All review feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to me as the review manager by email or by direct message. When emailing directly, please keep the proposal link at the top of the message.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

  • What is your evaluation of the proposal?
  • Is the problem being addressed significant enough to warrant a change to Swift?
  • Does this proposal fit well with the feel and direction of Swift?
  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at

https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

Joe Groff
Review Manager

6 Likes

Moderator note: this post was originally in the previous review thread and has been moved at the request of the author

The review period has ended, but since this is an ongoing discussion and there is no subsequent thread, I would like to put my opinion here.

I agree with @Jumhyn's point of view about as any P. I don't think it's fatal. But now I'm concerned, because users can run into this behavior from other sides. @Douglas_Gregor recently updated proposal about "Losing" constraints when type-erasing resulting values. From the discussion, the behavior is as following.

protocol P {
  associatedtype A
}
protocol Q {
  associatedtype B: P where B.A == Int
}
func getBFromQ<T: Q>(_ q: T) -> T.B { ... }
func eraseQAssoc(q: any Q) {
  let b = getBFromQ(q)
}

// then, user shave to use `as` coercion:
getBFromQ(q) as any P

However, what happens if there is another getP? I have no idea how the next code would work.

func getP<T: P>(_ p: T)
getP(getBFromQ(q) as any P)

If the compiler interprets this in a nice way it won't cause any compile error. If not, then, the user would get confused. Awfully, they gets another error when they remove as any P. Struggling, they will find the following code works fine, and they would start to write a bug report at this moment :memo:

let p = getBFromQ(q) as any P
getP(p)

In the case the compiler can behave in a nice way, then, I'm also curious how the following code works. In any case, this code must cause a compile error.

getP(getBFromQ(q) as any P as any P)

After all, I'm a bit doubtful about introducing as any P as coercion mechanism while it still works as normal cast mechanism. Not a strong opposition, though :thinking:

2 posts were merged into an existing topic: SE-0352: Implicitly Opened Existentials

Ah, this is a good point. as any P being used as two different kinds of a suppression mechanism (don't open the existential, don't complain about loss of information) is causing the collision here. We probably need to eliminate one of the meanings and come up with a different spelling for it.

Doug

4 Likes

OTOH: I think both meanings are reasonably expressed as as any P, and one of the meanings is intended to be a ~temporary state of affairs that will go away once the language has the ability to express the full-information types. I personally don't see the "pull it into a separate expression" solution:

as a dealbreaker (so long as we could reasonably offer this as a fix-it). I would (naïvely) expect the intersection of these two meanings to be pretty rare.

3 Likes

Thank you all for the feedback! The core team has reviewed this discussion. We agree that the as any P syntax is natural for both explicitly discarding constraints from return types, and for suppressing implicit opening of an existential argument, and that the likelihood of collision is low enough that it would be unfortunate to have to devise a different syntax for one or the other operation to avoid the unlikely collision. However, it is important that the implementation be able to avoid offering fixits that lead to invalid code, and that if a user ends up in this ambiguous situation, the compiler is able to diagnose and offer fixits describing what the user needs to do to get the desired behavior.

Breaking the expression up into two statements is a fine workaround for a human editor, but is a more difficult transform to generalize for an automatic fixit, so we would like to have a more localized mechanism for suppressing one of the behaviors that can be used by compiler fixits. The proposal author notes that putting parentheses around the argument, as in getP((getBFromQ(q) as any P)), is enough to make it so that the as any P is no longer directly applied to the call argument, and so would prevent it from suppressing the implicit opening behavior, and this syntax can be used when as any P is intended only to discard result constraints. Since this is a relatively minor change, the author has amended the proposal to discuss the ambiguity and specify additional parentheses as a way of suppressing the implicit opening behavior to avoid it. I will extend the review period for a week to allow the community to review this change. Thanks!

14 Likes

+1. I don't have the time to fully analyze the implications and possible corner cases, but it looks like an excellent way to help ease existential related issues.

I think answering "Why this works while that does not?" questions needs further attention in the compiler diagnostics, but we can improve it as we get experience with common tripping points.

+1 on this as well for resolving the ambiguity.