From e7c54157968428bc39b0cf373276081e362bf29e Mon Sep 17 00:00:00 2001 From: Ben Luo Date: Wed, 19 Oct 2022 14:03:33 +0800 Subject: [PATCH 1/3] add code tabs. --- .../scala3-book/methods-main-methods.md | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/_overviews/scala3-book/methods-main-methods.md b/_overviews/scala3-book/methods-main-methods.md index f88cebc16d..a33a1add6f 100644 --- a/_overviews/scala3-book/methods-main-methods.md +++ b/_overviews/scala3-book/methods-main-methods.md @@ -11,10 +11,16 @@ next-page: methods-summary 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: +{% tabs method_1 %} +{% tab 'Scala 3 Only' for=method_1 %} + ```scala @main def hello() = println("Hello, world") ``` +{% endtab %} +{% endtabs %} + Just save that line of code in a file named something like *Hello.scala*---the filename doesn’t have to match the method name---and run it with `scala`: ```bash @@ -36,6 +42,9 @@ Learn more about the `@main` annotation by reading the following sections, or by 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: +{% tabs method_2 %} +{% tab 'Scala 3 Only' for=method_2 %} + ```scala @main def happyBirthday(age: Int, name: String, others: String*) = val suffix = (age % 100) match @@ -51,6 +60,9 @@ For example, given this `@main` method that takes an `Int`, a `String`, and a va println(sb.toString) ``` +{% endtab %} +{% endtabs %} + When you compile that code, it creates a main program named `happyBirthday` that’s called like this: ``` @@ -73,8 +85,6 @@ $ scala happyBirthday sixty Fred Illegal command line: java.lang.NumberFormatException: For input string: "sixty" ``` - - ## The details The Scala compiler generates a program from an `@main` method `f` as follows: @@ -85,6 +95,9 @@ The Scala compiler generates a program from an `@main` method `f` as follows: For instance, the `happyBirthday` method above generates additional code equivalent to the following class: +{% tabs method_3 %} +{% tab 'Scala 3 Only' for=method_3 %} + ```scala final class happyBirthday { import scala.util.{CommandLineParser as CLP} @@ -104,12 +117,13 @@ final class happyBirthday { > This feature is not available for user programs in Scala. > Regular “static” members are generated in Scala using objects instead. - +{% endtab %} +{% endtabs %} ## Scala 3 compared to 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: +{% tabs method_4 class=tabs-scala-version %} +{% tab 'Scala 2' for=method_4 %} ```scala // scala 2 @@ -118,16 +132,26 @@ object happyBirthday extends App { } ``` -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. +{% endtab %} -If programs need to cross-build between Scala 2 and Scala 3, it’s recommended to use an explicit `main` method with an `Array[String]` argument instead: +{% tab 'Scala 3' for=method_4 %} ```scala object happyBirthday: def main(args: Array[String]) = println("Hello, world") ``` +> `@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 explicit `main` method with an `Array[String]` argument instead: + +{% endtab %} +{% endtabs %} + If you place that code in a file named *happyBirthday.scala*, you can then compile it with `scalac` and run it with `scala`, as shown previously: ```bash From 46f2a7e7db7538dd375abbf084d3b292b7d7832b Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Wed, 19 Oct 2022 09:55:54 +0200 Subject: [PATCH 2/3] correct outdated text --- _overviews/scala3-book/methods-main-methods.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/_overviews/scala3-book/methods-main-methods.md b/_overviews/scala3-book/methods-main-methods.md index a33a1add6f..c397c99230 100644 --- a/_overviews/scala3-book/methods-main-methods.md +++ b/_overviews/scala3-book/methods-main-methods.md @@ -8,6 +8,7 @@ previous-page: methods-most next-page: methods-summary --- +
Writing one line programs Scala 3 Only
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: @@ -15,17 +16,17 @@ Scala 3 offers a new way to define programs that can be invoked from the command {% tab 'Scala 3 Only' for=method_1 %} ```scala -@main def hello() = println("Hello, world") +@main def hello() = println("Hello, World") ``` {% endtab %} {% endtabs %} -Just save that line of code in a file named something like *Hello.scala*---the filename doesn’t have to match the method name---and run it with `scala`: +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`: ```bash $ scala Hello.scala -Hello, world +Hello, World ``` A `@main` annotated method can be written either at the top-level (as shown), or inside a statically accessible object. @@ -71,7 +72,7 @@ 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 an instance of the *scala.util.FromString* type class that converts an argument `String` to the required parameter type. +For each parameter type there must be a [given instance](./ca-given-using-clauses.html) 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. @@ -91,7 +92,7 @@ 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 Java `main` method: it takes an `Array[String]` as argument and returns `Unit`. -- The generated `main` method calls method `f` with arguments converted using methods in the `scala.util.CommandLineParser` object. +- The generated `main` method calls method `f` with arguments converted using methods in the `scala.util.CommandLineParser.FromString` object. For instance, the `happyBirthday` method above generates additional code equivalent to the following class: @@ -106,7 +107,7 @@ final class happyBirthday { happyBirthday( CLP.parseArgument[Int](args, 0), CLP.parseArgument[String](args, 1), - CLP.parseRemainingArguments[String](args, 2)) + CLP.parseRemainingArguments[String](args, 2)*) catch { case error: CLP.ParseError => CLP.showError(error) } From 6fd891557ec492b77fb2011f6f4277261abe2d61 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Wed, 19 Oct 2022 10:14:47 +0200 Subject: [PATCH 3/3] reframe scala 2 section as backward compat --- .../scala3-book/methods-main-methods.md | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/_overviews/scala3-book/methods-main-methods.md b/_overviews/scala3-book/methods-main-methods.md index c397c99230..acc0cc1c0b 100644 --- a/_overviews/scala3-book/methods-main-methods.md +++ b/_overviews/scala3-book/methods-main-methods.md @@ -1,5 +1,5 @@ --- -title: main Methods +title: Main Methods in Scala 3 type: section description: This page describes how 'main' methods and the '@main' annotation work in Scala 3. languages: [zh-cn] @@ -121,34 +121,30 @@ final class happyBirthday { {% endtab %} {% endtabs %} -## Scala 3 compared to Scala 2 +## Backwards Compatibility with Scala 2 -{% tabs method_4 class=tabs-scala-version %} -{% tab 'Scala 2' for=method_4 %} +`@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: -```scala -// scala 2 -object happyBirthday extends App { - // needs by-hand parsing of the command line arguments ... -} -``` +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. -{% endtab %} +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: -{% tab 'Scala 3' for=method_4 %} +{% tabs method_4 %} +{% tab 'Scala 2 and 3' %} ```scala -object happyBirthday: - def main(args: Array[String]) = println("Hello, world") +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:_*) +} ``` -> `@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 explicit `main` method with an `Array[String]` argument instead: +> note that here we use `:_*` to pass a vararg argument, which remains in Scala 3 for backwards compatibility. {% endtab %} {% endtabs %} @@ -158,6 +154,6 @@ If you place that code in a file named *happyBirthday.scala*, you can then compi ```bash $ scalac happyBirthday.scala -$ scala happyBirthday -Hello, world +$ scala happyBirthday 23 Lisa Peter +Happy 23rd Birthday, Lisa and Peter! ```