-
Notifications
You must be signed in to change notification settings - Fork 28
SIP-57 - Replace non-sensical @unchecked annotations #67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SIP-57 - Replace non-sensical @unchecked annotations #67
Conversation
f8c06f9
to
d28b69f
Compare
A bit of bike shedding, but all annotations that I can find in |
It's an |
I will need to add an amendment that we would also like to change the following behavior: scala> val xs = List(1: Any)
val xs: List[Any] = List(1)
scala> xs match {
| case is: ::[Int] => is.head
| }
2 warnings found
-- [E029] Pattern Match Exhaustivity Warning: ----------------------------------
1 |xs match {
|^^
|match may not be exhaustive.
|
|It would fail on pattern case: List(_, _*), Nil
|
| longer explanation available when compiling with `-explain`
val res11: Int = 1
-- Unchecked Warning: ----------------------------------------------------------
2 | case is: ::[Int] => is.head
| ^
|the type test for ::[Int] cannot be checked at runtime because its type arguments can't be determined from List[Any] when we try again with the scala> (xs: @unchecked) match {
| case is: ::[Int] => is.head
| }
val res12: Int = 1 with scala> xs.runtimeChecked match {
| case is: ::[Int] => is.head
| }
1 warning found
-- Unchecked Warning: ----------------------------------------------------------
2 | case is: ::[Int] => is.head
| ^
|the type test for ::[Int] cannot be checked at runtime because its type arguments can't be determined from List[Any]
val res13: Int = 1 This is because To fully avoid warnings, the scala> xs.runtimeChecked match {
| case is: ::[Int @unchecked] => is.head
| }
val res14: Int = 1 This has a small extra migration cost because if the scrutinee changes from Once again |
(I'm an assigned reviewer and manager for this SIP) I think purpose of this SIP is clearly explained and valid, and the proposed solution is good. The name @sjrd my understanding is that your concerns about breaking macros are resolved by the @Kordyjan as the other assigned reviewer, do you have any thoughts? Unless someone raises new concerns, I'm inclined to vote to approve this proposal at the next meeting. |
In Scala 3, // Scala 3
scala> def f(x: Any) = (x: @unchecked) match { case Some(_) => 0; case Some(1) => 1 } // no warning
def f(x: Any): Int Would that remain the same? Note that's different in Scala 2 where @bishabosha regarding this comment #67 (comment), in Scala 2 // Scala 2
scala> def f(xs: List[Any]) = (xs: @unchecked) match { case is: ::[Int] => is.head }
^
warning: non-variable type argument Int in type pattern scala.collection.immutable.::[Int] (the underlying of ::[Int]) is unchecked since it is eliminated by erasure
def f(xs: List[Any]): Int Maybe that can be considered a bug in Scala 3. |
To someone unfamiliar, But this is not the case. What it's doing is disabling compiletime exhaustivity checking. The warning for a non-exhaustive match says "match may not be exhaustive", so "exhaustive" is already a term that users need to learn. Can we use it in the new syntax introduced by this SIP, e.g. |
But the check is delayed, no? If we have a selector without a matching case, we get a |
It's maybe a matter of perspective; the runtime checks are always there and unchanged, whether we do the compiletime checks or not. |
Yes, but theoretically we could drop the |
The main thing here is that we tell the compiler that we want to wait until runtime to check this. So I think |
True, but that's purely an optimization; we'd still need to evaluate the last extractor to preserve semantics. Anyway, my main point is that |
But everything we do also has to work for the case of a val x: Any = ???
val y: Int = x.runtimeCheck is more obvious than val x: Any = ???
val y: Int = x.nonExhaustive |
There's no |
I like the idea of decoupling exhaustivity warnings and unchecked warnings resulting from type information being lost due to erasure. It was a mistake in the first place that Scala 3 uses a single annotation to silence both kinds of warnings. I have a slight problem with the name of the method, while val x :: tail = someList.runtimeCheck is intuitive; I agree with @lrytz that the distinction between I am for accepting this proposal, but I believe that we should spend some time before the vote to be sure we have chosen the best name for the method. |
I have integrated the comments about scala 2.13 behavior of unchecked, in comparison to the proposed semantics of |
So this will not bring in any runtime overhead?does runtime check means unsafecast? |
runtime bytecode is identical, it only silences the pattern match exhaustiveness check. |
If we are to solve the naming issue, then let's spell out some of the ways of interpreting the effect of
|
My favorite is actually the "assert" meaning. Mixed with the 3rd one I would actually think of it as "assert exhaustive". Then I'm wondering if it should throw an |
I was thinking about |
What about
|
I'm for xs.assume match
case x0 :: tail => ???
val x0 :: tail = xs.assume
assume(xs) match
case x0 :: tail => ???
val x0 :: tail = assume(xs) look pretty good. And I agree that |
Hmm... But |
I think I prefer @JD557's suggestion |
There is the possibility that we want to expand this further. We now allow: val (x: T) = y.runtimeChecked since val x: T = y.runtimeChecked With To be sure, this is not part of the current SIP, but it would be a likely next step. I still think |
I like the trailing |
I'm fine with |
I'm pleased to announce that the SIP Committee voted in favor of this SIP to be "Accepted for implementation" |
Is there a precedent for using annotations to rewrite expressions?, i.e. would this val x: T = y: @RuntimeChecked // inlining of y.runtimeChecked rewrite to val x: T = y match
case y: T => y
case _ => throw ClassCastException(...) do we need another primitive? should we add type parameters? |
Currently, a user can silence warnings that a scrutinee may not be matched by a pattern, by annotating the scrutinee with the
@unchecked
annotation.This SIP proposes to use a new annotation
@RuntimeCheck
to replace@unchecked
for this purpose. For convenience, an extension method will be added toPredef
that marks the receiver with the annotation (used as follows:foo.runtimeCheck
).Functionally it behaves the same as the old annotation, but improves readability at the callsite.