Skip to content
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

Improve usability of erased values #4759

Merged
merged 4 commits into from
Jul 4, 2018
Merged

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Jul 4, 2018

Erased values were not very useful so far:

  • we could not instantiate them with anything interesting without triggering a warning.
  • we could not pull out a type from them without getting an error.

Both impediments are fixed in this PR. This is an alternate fix for #4060.

odersky added 3 commits July 4, 2018 16:47
`erased` is really the same thing as `lazy` or by-name. The semantics
implies it will not be evaluated. So it is pointless to warn if an impure
expression is passed to an erased val or parameter. Moreover, erased initializers
are often complex expressions - after all if they were not, why erase them
in the first place? These expressions are almost never recognized as pure given
the weak effect checking we currently have. So the warnings are issued
in the common case, which is bad.
In that sense they behave exactly like lazy vals. Making them unstable threw out most
use cases. We typically set up an erased value because it contains interesting types.
But to get at the types the values have to be stable in the first place!
I noticed a REPL crash because we triggered the error condition
but there was no source associated with context.owner.
Flag `|` is not super-fast, so it might pay to compute this once ahead of time.
Copy link
Contributor

@nicolasstucki nicolasstucki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation-wise it LGTM

@Blaisorblade
Copy link
Contributor

👍 from me (a posteriori). I thought I had found an escape, but it seems this check is even more robust than expected. However, the fact that cast1 is unsafe still makes this pretty fragile to work with.

abstract class <:<[A, B] {
  type T >: A <: B
}
def cast1[A, B](x: A)(erased y: A <:< B): B = x.asInstanceOf[B] //should be safe, but isn't
def cast2[A, B](x: A)(erased y: A <:< B): B = x: y.T // error

cast1[Int, String](1)(???) // crashes
cast2[Int, String](1)(???) // error

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants