Description
This is only concerned with a way to migrate scala 3
versions to scala 3.5+
and above. An alternate title for this might be:
Provide a way to execute scripts with ".sc" extension as ".scala" files
Migrating a project with many legacy scripts requires that when bugs are encountered in production, a script can be reverted by editing the hash-bang
line, and without being renamed. Also, some scripts cannot be renamed, even after the migration period, so the scala_legacy
script isn't a universal option.
The need is for a way to optionally treat some .sc
scripts as if they have the .scala
filename extension.
Prior to scala 3.5
all scripts require a main method, so a migration format that can easily switch between old and new script semantics requires a main method.
The primary challenge is that after 3.5
, the main method is not automatically called unless the file is renamed. In other words, the main method is never called if a script has the .sc
extension.
Example hypothetical migration format (almost adequate, but has non-portable element on line 5 Main.main(args)
.
#!/usr/bin/env -S scala-cli shebang
//> using scala 3.4.3
//> using dep "com.lihaoyi::os-lib::0.11.3"
import os._
Main.main(args) // required by `3.5+`, rejected by earlier scala versions
object Main {
def main(args: Array[String]): Unit =
val root1 = os.root("C:\\")
printf("cRoot: %s\n", root1)
}
Describe the solution you'd like
Possible approaches to specifying the proposed .scala
mode option:
scala-cli
command line, similar to--main-class
(maybe--main-method
)- system property ( "scala.dot_scala_extension")
- alternate supported extension such as
.sc_
or similar, treated as if.scala
- comment
//> using scala-extension-semantics
Describe alternatives you've considered
Adding support for a new filename extension .sc_
turned out to be pretty simple, and seems to work nicely, although it doesn't address the case of scripts that cannot easily be renamed. Here's the implementation:
# git diff
diff --git a/modules/build/src/main/scala/scala/build/input/Inputs.scala b/modules/build/src/main/scala/scala/build/input/Inputs.scala
index 8e93d1463..4d5b44e55 100644
--- a/modules/build/src/main/scala/scala/build/input/Inputs.scala
+++ b/modules/build/src/main/scala/scala/build/input/Inputs.scala
@@ -275,8 +275,8 @@ object Inputs {
}
else if path.last == Constants.projectFileName then
Right(Seq(ProjectScalaFile(dir, subPath)))
+ else if arg.endsWith(".scala") || arg.endsWith(".sc_") then Right(Seq(SourceScalaFile(dir, subPath)))
else if arg.endsWith(".sc") then Right(Seq(Script(dir, subPath, Some(arg))))
- else if arg.endsWith(".scala") then Right(Seq(SourceScalaFile(dir, subPath)))
else if arg.endsWith(".java") then Right(Seq(JavaFile(dir, subPath)))
else if arg.endsWith(".jar") then Right(Seq(JarFile(dir, subPath)))
else if arg.endsWith(".c") || arg.endsWith(".h") then Right(Seq(CFile(dir, subPath)))
Experiments were done based on various wrappers around scala-cli
, the two most successful described here.
- create an on-the-fly symlink in the script parent directory, but with
.scala
extension, which is deleted-on-exit - wrapper to pipe the script to scala-cli STDIN: (similar to
echo 'println("Hello, Scala!")' | scala-cli -
)
Approach 1 works well most of the time, but after a crash, symlinks tend to be left behind.
The pipe-to-stdin approach is equivalent to the following conversion:
jsrc/sum.sc 1 2 3
# the equivalent command line when piped to `scala-cli` <stdin>:
tail -n +2 jsrc/sum.sc | scala-cli run -Dscript.path=jsrc/sum.sc @/opt/ue3cps _.scala -- 1 2 3
It works much of the time, but isn't viable for interactive scripts, or those that read from stdin
.
The minimum startup time with this approach is about 10.0 seconds, and if procPipe.sc
is compiled, about 8.0 seconds.
For comparison, the equivalent .scala
version of the script starts up in less than 4 seconds, and under 1 second after it's been compiled.
Additional context
I work with projects having 1400+ legacy scripts, only about 20% have been migrated to scala 3.6.3.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status