Closed mpilquist closed 1 week ago
@mpilquist what semantics would you expect from top-level opaque types in the REPL?
I would expect scoped to the line:
scala> opaque type T = String ; def f: T = "hi"
similar to
scala> def f(s: String): Int = s.toInt ; def f(i: Int): Int = i+1 // ok, not local statements
I may not know whether or how a given line is wrapped.
I wanted to enter both an opaque type and a companion, which is currently prohibited, even if wrapping with an outer { /* put type and companion here */ }
Yeah, I guess that makes sense. One may also want to copy top-level code from a file into a REPL, and we can define top-level opaque types in files.
In principle I think this should work, in practice it may boil down to how REPL encodes lines. I think right now every input corresponds to a class' body, which would imply we'd somehow need to add extra support for opaque types in class bodies.
How does REPL encode opaque type T = Int
?
Just wrap it in class REPL{ }
or something like that? That seems to be fine for opaque types.
How does REPL encode
opaque type T = Int
?Just wrap it in
class REPL{ }
or something like that? That seems to be fine for opaque types.
it should be fine I think
scala> /*opaque*/ type T = Int
| object T:
| def apply(i: Int): T = i
|
result of rs$line$1 after typer:
package repl$ {
final lazy module val rs$line$1: repl$.rs$line$1$ = new repl$.rs$line$1$()
final module class rs$line$1$() extends Object() {
this: repl$.rs$line$1.type =>
type T = Int
final lazy module val T: T$ = new T$()
final module class T$() extends Object() { this: T.type =>
def apply(i: Int): T = i
}
}
}
Yeah, I guess that makes sense. One may also want to copy top-level code from a file into a REPL, and we can define top-level opaque types in files.
In principle I think this should work, in practice it may boil down to how REPL encodes lines. I think right now every input corresponds to a class' body, which would imply we'd somehow need to add extra support for opaque types in class bodies.
Btw, this works correctly in the Scala 2 REPL, and what I mean by that is when you paste a multi-line block of code it doesn't get processed as line-prompt-line-... but as a single snippet. So bringing forward that support would deal with that use case.
[edit: actually looks like the Scala 3 REPL already does support that.]
Note that in both Scala 2 and Scala 3, the REPL allows you (because JLine 3 allows you) to press option-Return to continue the current input. (Rendering Scala 2's :paste
unneeded, unless you need :paste -raw
.)
Just to add my two cents, I have an admittedly weird use case for the REPL supporting opaque types.
I maintain a tut-like tool: a tool that runs a REPL session, passes Scala blocks it finds in a markdown file, and pastes the result in an output markdown file. I use this to generate slides, articles, ... and be fully confident that my code samples are valid.
The REPL not supporting opaque types means I can't use my tools to use or explain opaque types to Scala beginners.
This is a weird, very niche use case that nobody else might have. Just thought it might be interesting to share.
Perhaps mdoc (the standard "tut-like" tool these days, now that tut is deprecated) is affected as well?
I don't think so - it's my understanding that mdoc doesn't run a REPL session, but generates classes and runs a normal compiler.
Still valid.
scala repl -S 3.nightly
# Welcome to Scala 3.6.0-RC1-bin-20240703-75a15c2-NIGHTLY-git-75a15c2 (17, Java OpenJDK 64-Bit Server VM).
# Type in expressions for evaluation. Or try :help.
#
# scala> opaque type T = Int
# -- [E103] Syntax Error: --------------------------------------------------------
# 1 |opaque type T = Int
# |^^^^^^
# |Illegal start of statement: this modifier is not allowed here
# |
# | longer explanation available when compiling with `-explain`
#
# scala>
While of course:
scala compile --scala-snippet 'opaque type T = Int' -S 3.nightly
# Compiling project (Scala 3.6.0-RC1-bin-20240703-75a15c2-NIGHTLY, JVM (17))
# Compiled project (Scala 3.6.0-RC1-bin-20240703-75a15c2-NIGHTLY, JVM (17))
Minimized code