This doc page is specific to Scala 3, and may cover new concepts not available in Scala 2. Unless otherwise stated, all the code examples in this page assume you are using Scala 3.
Writing one line programs
Scala 3 offers a new way to define programs that can be invoked from the command line: Adding a @main
annotation to a method turns it into entry point of an executable program:
@main def hello() = println("Hello, World")
To run this program, save the line of code in a file named as e.g. Hello.scala—the filename doesn’t have to match the method name—and run it with scala
:
$ scala run Hello.scala
Hello, World
A @main
annotated method can be written either at the top-level (as shown), or inside a statically accessible object.
In either case, the name of the program is in each case the name of the method, without any object prefixes.
Learn more about the @main
annotation by reading the following sections, or by watching this video:
Command line arguments
With this approach your @main
method can handle command line arguments, and those arguments can have different types.
For example, given this @main
method that takes an Int
, a String
, and a varargs String*
parameter:
@main def happyBirthday(age: Int, name: String, others: String*) =
val suffix = (age % 100) match
case 11 | 12 | 13 => "th"
case _ => (age % 10) match
case 1 => "st"
case 2 => "nd"
case 3 => "rd"
case _ => "th"
val sb = StringBuilder(s"Happy $age$suffix birthday, $name")
for other <- others do sb.append(" and ").append(other)
println(sb.toString)
Pass the arguments after --
:
$ scala run happyBirthday.scala -- 23 Lisa Peter
Happy 23rd Birthday, Lisa and Peter!
As shown, the @main
method can have an arbitrary number of parameters.
For each parameter type there must be a given instance of the scala.util.CommandLineParser.FromString
type class that converts an argument String
to the required parameter type.
Also as shown, a main method’s parameter list can end in a repeated parameter like String*
that takes all remaining arguments given on the command line.
The program implemented from an @main
method checks that there are enough arguments on the command line to fill in all parameters, and that the argument strings can be converted to the required types.
If a check fails, the program is terminated with an error message:
$ scala run happyBirthday.scala -- 22
Illegal command line after first argument: more arguments expected
$ scala run happyBirthday.scala -- sixty Fred
Illegal command line: java.lang.NumberFormatException: For input string: "sixty"
User-defined types as parameters
As mentioned up above, the compiler looks for a given instance of the
scala.util.CommandLineParser.FromString
typeclass for the type of the
argument. For example, let’s say you have a custom Color
type that you want to
use as a parameter. You would do this like you see below:
enum Color:
case Red, Green, Blue
given CommandLineParser.FromString[Color] with
def fromString(value: String): Color = Color.valueOf(value)
@main def run(color: Color): Unit =
println(s"The color is ${color.toString}")
This works the same for your own user types in your program as well as types you might be using from another library.
The details
The Scala compiler generates a program from an @main
method f
as follows:
- It creates a class named
f
in the package where the@main
method was found. - The class has a static method
main
with the usual signature of a Javamain
method: it takes anArray[String]
as argument and returnsUnit
. - The generated
main
method calls methodf
with arguments converted using methods in thescala.util.CommandLineParser.FromString
object.
For instance, the happyBirthday
method above generates additional code equivalent to the following class:
final class happyBirthday {
import scala.util.{CommandLineParser as CLP}
<static> def main(args: Array[String]): Unit =
try
happyBirthday(
CLP.parseArgument[Int](args, 0),
CLP.parseArgument[String](args, 1),
CLP.parseRemainingArguments[String](args, 2)*)
catch {
case error: CLP.ParseError => CLP.showError(error)
}
}
Note: In this generated code, the
<static>
modifier expresses that themain
method is generated as a static method of classhappyBirthday
. This feature is not available for user programs in Scala. Regular “static” members are generated in Scala using objects instead.
Backwards Compatibility with Scala 2
@main
methods are the recommended way to generate programs that can be invoked from the command line in Scala 3.
They replace the previous approach in Scala 2, which was to create an object
that extends the App
class:
The previous functionality of App
, which relied on the “magic” DelayedInit
trait, is no longer available.
App
still exists in limited form for now, but it doesn’t support command line arguments and will be deprecated in the future.
If programs need to cross-build between Scala 2 and Scala 3, it’s recommended to use an object
with an explicit main
method and a single Array[String]
argument instead:
object happyBirthday {
private def happyBirthday(age: Int, name: String, others: String*) = {
... // same as before
}
def main(args: Array[String]): Unit =
happyBirthday(args(0).toInt, args(1), args.drop(2).toIndexedSeq:_*)
}
note that here we use
:_*
to pass a vararg argument, which remains in Scala 3 for backwards compatibility.
If you place that code in a file named happyBirthday.scala, you can then compile and run it with scala
, as shown previously:
$ scala run happyBirthday.scala -- 23 Lisa Peter
Happy 23rd Birthday, Lisa and Peter!