Opaque types and inline defs limitation #82
Comments
This will be next to impossible to achieve. Opaque types rely on location for type-checking. Inline methods rely on moving code to the caller. I see no way to (re-)typecheck inlined code at the call site and at the same time keep typing as if it was at the original location. |
Does this mean refinement types are next to impossible with scala3? At least using opaque types? |
They will be possible, but via literal-type operations. We just need to add an |
@kwark You could potentially move your inlines to where opaque type are not visible: package example
type X = x.X
object X {
inline def apply ...
private[example] object x {
opaque type X
}
} |
Following @neko-kai example, since the desired behaviour can be achieved by introducing an extra scope which hides the opaque type, would it be possible to use a simmilar approach internally in the compiler? I can easily see programmers failing on this particular feature while implementing their own refined types. |
I came up with: import scala.compiletime.*
opaque type Positive = Long
object Positive extends PositiveRefined:
private[refined] def unsafe(input: Long): Positive = input
trait PositiveRefined:
def safe(v: Long): Positive | IllegalArgumentException =
if v >= 0 then Positive.unsafe(v)
else IllegalArgumentException("value must be >= 0")
inline def refine(inline v: Long): Positive =
if v >= 0 then Positive.unsafe(v)
else error("value must be >= 0") And, to use it: val positive: Positive = Positive.refine(1) //compiles just fine
val negative: Positive = Positive.refine(-1) //compilation error: value must be >= 0
val runtimeLong = 10L
Positive.safe(runtimeLong) match
case p: Positive => ???
case e: IllegalArgumentException => ??? AFAIK no boxing is being made at runtime whatsoever if we use the |
@gabfssilva |
After this PR, the other way around would be this: opaque type Positive = Long
object Positive:
private[refined] def unsafe(input: Long): Positive = input
object PositiveRefined:
def safe(v: Long): Positive | IllegalArgumentException =
if v >= 0 then Positive.unsafe(v)
else IllegalArgumentException("value must be >= 0")
inline def refine(inline v: Long): Positive =
if v >= 0 then Positive.unsafe(v)
else error("value must be >= 0") and then, instead of |
Good news: Once scala/scala3#12815 is merged, the restriction will be lifted. So no workarounds are needed anymore. |
Thank you so much Martin! It's nice to see a PR going from more restriction to no restriction at all 👍 |
Thank you so much for the work on this @odersky! I think opaque type and inline def go together pretty naturally. Also it's awkward to have language features that don't compose. I think this simplifies the teaching of scala 3. |
Fixed by scala/scala3#12815 |
Tried to use opaque types to create a compile time constrained
Positive
integer type:Unfortunately I got the error
Implementation restriction: No inline methods allowed where opaque type aliases are in scope
.Please remove this restriction.
The text was updated successfully, but these errors were encountered: