Skip to content

v1.17.0

Pre-release
Pre-release

Choose a tag to compare

@Gedochao Gedochao released this 08 Sep 12:54
3c94861

Changed defaults to Scala 3.9.0 LTS & lts tags now point at the 3.9 LTS series

Scala 3.9.0 is both the new default Scala version and the first in line of the new Long Term Support series, so the lts version tags
(as passed to -S / --scala-version or the //> using scala directive) now resolve to 3.9 rather than 3.3.
Additionally, <prefix>.lts tags are now recognised for any supported LTS series, which lets you pin the older 3.3 LTS
explicitly.

Tag Before After
lts, 3.lts 3.3.8 3.9.0
lts.rc, 3.lts.rc latest 3.3 RC latest 3.9 RC
lts.nightly, 3.lts.nightly 3.3 nightly 3.9 nightly
3.3.lts, 3.3.lts.rc, 3.3.lts.nightly not recognised the 3.3 series
3.9.lts, 3.9.lts.rc, 3.9.lts.nightly not recognised the 3.9 series
3.7.lts (and other non-LTS <prefix>.lts) not recognised not recognised
scala-cli -e 'println(scala.util.Properties.versionNumberString)' -S lts
# Compiling project (Scala 3.9.0, JVM (25))
# Compiled project (Scala 3.9.0, JVM (25))
# 3.9.0
scala-cli -e 'println(dotty.tools.dotc.config.Properties.simpleVersionString)' -S 3.3.lts --with-compiler
# Compiling project (Scala 3.3.8, JVM (25))
# Compiled project (Scala 3.3.8, JVM (25))
# 3.3.8

Added by @Gedochao in #4442 and #4443

JEP 512 flexible main methods

Scala CLI now recognises and launches JEP 512 main methods when targeting the JVM:
static or instance main methods, with or without a String array parameter, and regardless of whether they are
public. This requires JDK 25 or newer (or JDK 21+ with the --enable-preview Java option), and works for both Scala and Java sources.

//> using jvm 25
class HelloJep512:
  def main(): Unit = println("Hello from a JEP 512 instance main!")
scala-cli run HelloJep512.scala
# Hello from a JEP 512 instance main!

On JDK 21 through 24 the same code runs as long as preview features are enabled:

//> using jvm 21
//> using javaOpt --enable-preview
class HelloJep512:
  def main(): Unit = println("Hello on JDK 21 preview")

Such main methods are also detected when inherited from a Java class or interface:

//> using jvm 25
public abstract class Greeter {
  void main() {
    System.out.println("Hello from an inherited JEP 512 instance main!");
  }
}
public class HelloJava extends Greeter {}
scala-cli run java-demo --main-class HelloJava
# Hello from an inherited JEP 512 instance main!

On older JDKs detection still happens, so instead of a bare No main class found you now get an actionable message:

[error]  No main class found
Class Hello declares a main method that requires JDK 25 or newer (JEP 512); the current JVM is 17.

Note: the default package bootstrap launcher cannot launch JEP 512 main methods as of yet, use --assembly or --library
instead. Scala.js and Scala Native are not supported for those, either.

Added by @Gedochao and @warcholjakub in #4418, #4425, #4424 and #4430

Individual files as resources

It is now possible to pass individual files (and not only directories) as resources via the --resource command line option and the //> using resource. A file passed this way lands at the root of the class path under its own name.

Hello from an individual resource file!
object ReadResource:
  def main(args: Array[String]): Unit =
    val stream = getClass.getClassLoader.getResourceAsStream("greeting.txt")
    println(scala.io.Source.fromInputStream(stream).mkString.trim)
scala-cli run ReadResource.scala --resource greeting.txt
# Hello from an individual resource file!

Note that a single file can now also be passed to the old --resource-dir option and //> using resourceDir directive.

scala-cli run ReadResource.scala --resource-dir greeting.txt
# Hello from an individual resource file!

Added by @Gedochao in #4428

Library JARs from -d destinations ending with .jar

When the destination passed to -d / --compilation-output ends with .jar, Scala CLI now packages the compilation
results as a library JAR (the same contents as package --library) rather than writing class files into a directory
of that name. This mirrors scalac -d out.jar, so it does not require --power.

object Greeter:
  def greeting: String = "Hello from a packaged library JAR!"
scala-cli compile Greeter.scala -d greeter.jar
scala-cli -e 'println(Greeter.greeting)' --extra-jars greeter.jar

Added by @Gedochao in #4426

The //> using exclude directive in .sc scripts

The //> using exclude directive used to be accepted only in the project.scala configuration file. It can now live
in any .sc script instead — still in just one place per project, so it stays unambiguous. When both a project.scala
and scripts declare excludes, the outermost project.scala wins.

this is not valid Scala at all
//> using exclude broken.scala
println("Hello from a script declaring an exclude directive!")
scala-cli run script-demo

Added by @Gedochao in #4429 and #4437

Features

  • Support JEP 512 flexible main methods on JDK 25+ / JDK21+ with --enable-preview by @Gedochao in #4418
  • Auto detect user-created main methods in classes named with the *$_ suffix by @Gedochao in #4424
  • Package --library JAR files when -d is set to a *.jar path by @Gedochao in #4426
  • Allow the //> using exclude directive in an .sc script rather than just project.scala (but still only one place) by @Gedochao in #4429
  • fix: non-public main detection (JEP 512) by @warcholjakub in #4430
  • Add support for passing individual files as resources by @Gedochao in #4428
  • Auto detect main methods inherited from Java sources (including JEP 512 ones) by @Gedochao in #4425
  • Switch lts tags to Scala 3.9 series by @Gedochao in #4443

Fixes

Build and internal changes

Updates

New Contributors

Full Changelog: v1.16.0...v1.17.0