diff --git a/website/docs/guides/intro.md b/website/docs/guides/intro.md index c3dc3d7ae1..c3e86da806 100644 --- a/website/docs/guides/intro.md +++ b/website/docs/guides/intro.md @@ -23,6 +23,7 @@ These few guides are a good starting point when learning how to use Scala CLI. - [`using` directives](./using-directives.md) - Scala CLI’s syntax that lets you store configuration information directly in source files - [IDE support](./ide.md) - how to import and use Scala CLI-based projects in your favorite IDE. +- [Migrating from the old `scala` runner](./old-runner-migration.md) - an in-depth look at all the differences between Scala CLI and the old `scala` script. ## Scripting guides diff --git a/website/docs/guides/old-runner-migration.md b/website/docs/guides/old-runner-migration.md new file mode 100644 index 0000000000..7681df0877 --- /dev/null +++ b/website/docs/guides/old-runner-migration.md @@ -0,0 +1,381 @@ +--- +title: Migrating from the old Scala runner +sidebar_position: 15 +--- + +import {ChainedSnippets} from "../../src/components/MarkdownComponents.js"; + +# Migrating from the old `scala` runner + +As of [SIP-46](https://github.com/scala/improvement-proposals/pull/46), Scala CLI has been accepted as the new `scala` +command. + +In that context, the purpose of this guide is to highlight the key differences between the old `scala` script +and Scala CLI to make the migration as smooth as possible for users. + +:::note +If you are looking for an overview of Scala CLI basics, refer to [the Basics page](../commands/basics.md). +If you merely want to get started with Scala CLI, you might want to first look +at [the Getting started page](../getting_started.md). +::: + +## How to test Scala CLI as the new `scala` command? + +There is a dedicated `scala-experimental` distribution of Scala CLI, which can install it as `scala` on your machine. +For instructions on how to try it out, refer to [the relevant doc](../reference/scala-command/index.md). + +## How has the passing of arguments been changed from the old `scala` runner to Scala CLI? + +Let us take a closer look on how the old runner handled arguments when compared to Scala CLI. + +### The old ways + +In the old `scala` runner, the first argument was treated as the input source, while the second and following arguments +were considered program arguments. + +```bash ignore +scala Source.scala programArg1 programArg2 +``` + +Since everything after the first argument had to be arbitrarily read as a program argument, regardless of format, all +runner options had to be passed before the source input. + +```bash ignore +scala -save script.sc programArg1 programArg2 +``` + +### The ways of Scala CLI + +With Scala CLI's default way of handling arguments, inputs and program arguments have to be +divided by `--`. There is no limit for the number of either. + +```bash ignore +scala-cli Source1.scala Source2.scala -- programArg1 programArg2 +``` + +Additionally, a Scala CLI sub-command can be passed before the inputs section. +For example, to call the above example specifying the `run` sub-command explicitly, pass it like this: + +```bash ignore +scala-cli run Source1.scala Source2.scala -- programArg1 programArg2 +``` + +More on sub-commands can be found [here](../commands/basics.md). + +Runner options can be passed on whatever spot in the inputs section (before `--`). +For example, all the following examples are correct ways to specify the Scala version explicitly as `3.2` + +```bash ignore +scala-cli -S 3.2 Source1.scala Source2.scala -- programArg1 programArg2 +scala-cli Source1.scala -S 3.2 Source2.scala -- programArg1 programArg2 +scala-cli Source1.scala Source2.scala -S 3.2 -- programArg1 programArg2 +``` + +:::note +The exception to this rule are the launcher options, like `--power` or `--cli-version`. +Those have to be passed before the inputs section (before any source inputs). + +For example, to explicitly specify the launcher should run Scala CLI `v0.1.20`, pass it like this: + +```bash ignore +scala-cli --cli-version 0.1.20 Source1.scala Source2.scala -- programArg1 programArg2 +``` + +Also, if a Scala CLI sub-command is being passed explicitly, all launcher options have to be passed before the +sub-command. This is especially important for `power` mode commands, as those need to be called with the `--power` +launcher option. + +For example, to call [the `package` sub-command](../commands/package.md), do it like this: + +```bash +scala-cli --power package --help +``` + +::: + +### The Scala CLI `shebang` sub-command + +To provide better support for shebang scripts, Scala CLI +has [a dedicated `shebang` sub-command](../commands/shebang.md), which handles arguments similarly to the old `scala` +script. + +```bash ignore +scala-cli shebang Source.scala programArg1 programArg2 +``` + +The purpose of the `shebang` sub-command is essentially to only be used in a shebang header (more +details on that can be found [in a later section of this guide](#example-shebang-script-with-scala-cli) or in the +separate [shebang scripts' guide](./shebang.md)), but nothing is really stopping you from using it from the command +line, if you're used to how the old `scala` runner handled arguments. Just bear in mind that it is not the intended user +experience. + +## How are the old `scala` runner options supported? + +For backwards compatibility's sake, Scala CLI accepts all the old `scala` runner options, although many of them have +been deprecated and are no longer supported in the new runner. This includes accepting all the Scala `2.13.x` and `3.x` +respective runners' specific options. + +### Fully supported old `scala` runner options + +The following old `scala` runner options are fully supported by Scala CLI, meaning that they deliver similar or expanded +functionalities with backwards-compatible syntax: + +- `-e`, which is an alias for Scala CLI's `--execute-script` and a close synonym + for [`--script-snippet`](../guides/snippets.md#examples) +- `-v` / `-verbose` / `--verbose`, which can be passed multiple times with Scala CLI, increasing the verbosity +- `-cp` / `-classpath` / `--class-path`, which adds compiled classes and jars to the class path +- `-version` / `--version`, which prints the currently run Scala CLI [version information](../commands/version.md) +- `-with-compiler`, which adds the Scala compiler dependency to the Scala CLI project +- Scala compiler options (with some requiring to be passed with `-O`, more info + in [the section below](#scala-compiler-options)) +- `-J` Java options +- `-Dname=prop` Java properties + +### Old `scala` runner options which have a different meaning in Scala CLI + +The following old `scala` runner options not only are not supported with their old functionalities, but have a different +meaning in Scala CLI: + +- `-i`, which is now an alias for Scala CLI's [`--interactive` mode](../reference/cli-options.md#--interactive) +- `-h` / `-help` + - in the old Scala `2.13.x` `scala` runner, it used to print the help of the runner + - in the old Scala `3.x` `scala` runner however, it used to print the Scala compiler help instead + - Scala CLI takes an approach similar to the old Scala `2.13.x` runner, and it prints Scala CLI help + - to view the Scala compiler help with Scala CLI, pass + the [--scalac-help](../commands/compile.md#scala-compiler-help) option instead + +### Deprecated and unsupported old `scala` runner options + +The following old `scala` runner options have been deprecated and even though they are accepted by Scala CLI (passing +them will not cause an error), they are ignored with an appropriate warning: + +- `-save`, refer to [the `package` sub-command](../commands/package.md#library-jars) on how to package a Scala CLI + project to a JAR +- `-nosave`, a JAR file is now never saved unless [the `package` sub-command](../commands/package.md) is called +- `-howtorun` / `--how-to-run` + - Scala CLI assumes how a file is to be run based on its file extension (and optionally its shebang header). This + cannot be overridden with a command line option, so ensure your inputs use the correct file extension or have + the [shebang header](#example-shebang-script-with-scala-cli) defined. This is sort of the equivalent of the + old `-howtorun guess`. + - To run the `REPL`, refer to [the `repl` sub-command](../commands/repl.md) + - This option has been largely replaced with Scala CLI's [sub-commands](../commands/basics.md) +- `-I`, to preload the extra files for the `REPL`, try passing them as inputs + for [the repl sub-command](../commands/repl.md) +- `-nc` / `nocompdaemon`, the underlying script runner class can no longer be picked explicitly, as with the old `scala` + runner +- `-run` - Scala CLI does not support explicitly forcing the old run mode. Just pass your sources as inputs and ensure + they are in the correct format and extension. + +### Scala compiler options + +All compiler options are supported when passed with the `--scalac-option` flag (or the `-O` alias for short). +However, many compiler options can also be passed directly. +For more information, refer +to [the Scala compiler options section of the `compile` sub-command doc](../commands/compile.md#scala-compiler-options). + +## How does Scala CLI detect if it's running a script or a main method? + +To answer this question, some disambiguation is necessary. +The most important thing to note is that this has been handled differently by the 2 old `scala` runners (for +Scala `2.13.x` and for `3.x`), so a +consistent behaviour hasn't really been established before Scala CLI. + +The Scala `2.13.x` old `scala` runner was the most flexible, automatically detecting if what is being run is a script or +an +object based on the source contents. This automatic detection was also possible to be overridden with the `-howtorun` +runner option (which has been +deprecated and is not supported in Scala CLI, +as [noted in an earlier section](#deprecated-and-unsupported-old-scala-runner-options)). +This also means that the `2.13.x` old `scala` runner did not really care about file extensions much. + +In contrast, the Scala `3.x` old `scala` runner relied on file extensions, with some extra consideration for the +presence of a +shebang header. Additionally, the Scala `3.x` old runner also inspected for main method definitions in `.sc` files, +including those +using [the Scala 3 idiomatic `@main` annotation](https://docs.scala-lang.org/scala3/book/methods-main-methods.html). +This means that the Scala `3.x` runner respected main methods defined in `.sc` files, but not scripts in `.scala` files. + +Scala CLI's approach is perhaps the most restrictive here. +It accepts explicitly defined main methods in `.scala` sources and script syntax in `.sc` sources, without any +additional flexibility. +The only exception would be files with a shebang header ran with the `shebang` sub-command, which are treated as +scripts (more details about this can be found [in [the shebang scripts' guide](./shebang.md)]). + +Now, to give some examples. + +### Main class in a `.scala` input + +Of course, the simplest case is putting a main class into a `.scala` source, which is supported by both of the old +runners and by Scala CLI. + +```scala title=Main.scala +object Main { + def main(args: Array[String]): Unit = println(args.mkString(" ")) +} +``` + + + +```bash +scala Main.scala Hello world +scala-cli Main.scala -- Hello world +``` + +```text +Hello world +``` + + + +### Main class in a `.sc` input + +```scala title=main-in-script.sc +object Main { + def main(args: Array[String]): Unit = println(args.mkString(" ")) +} +``` + +This case has been supported by both of the old `scala` runners, but is not supported by Scala CLI, which expects a +script in a `.sc` input and wraps its contents in a main class of its own, not inspecting further for a nested one. +In other words, when explicitly declaring a main class when working with Scala CLI, you have to do it in a `.scala` +file. + +```bash +scala-cli main-in-script.sc -- Hello world +# no output will be printed +``` + +Running such an `.sc` file will not fail by the way, but neither will it print any output, since the appropriate method +hasn't been called explicitly in the script. + +### Script syntax in an `.sc` file + +```scala title=script.sc +println(args.mkString(" ")) +``` + +This syntax is supported by the old Scala `2.13.x` runner, but **not** by the old Scala `3.x` one. +The Scala `3.x` runner does not allow for top level definitions without an explicit main class. + +However, it is supported by Scala CLI. + + + +```bash +scala-cli script.sc -- Hello world +``` + +```text +Hello world +``` + + + +### Script syntax in a `.scala` file + +Now for the inverted case, where script-style top level definitions are put in a `.scala` input. + +```scala title=script.scala +println(args.mkString(" ")) +``` + +This has actually been supported by the old Scala `2.13.x` runner. +However, both the old Scala `3.x` runner as well as Scala CLI do not support it. + + + +```bash fail +scala-cli script.scala -- Hello world +``` + +```text +[error] ./ScriptInScala.scala:1:1 +[error] Illegal start of toplevel definition +[error] println(args.mkString(" ")) +[error] ^^^^^^^ +Error compiling project (Scala 3.2.2, JVM) +Compilation failed +``` + + + +### Inputs with no extension + +```scala title=no-extension-script +println(args.mkString(" ")) +``` + +```scala title=no-extension-main-class +object Main { + def main(args: Array[String]): Unit = println(args.mkString(" ")) +} +``` + +Files with no extensions have been supported in the `2.13.x` old runner, but not in `3.x`. + +Script syntax in files with no extension (or with extensions not indicating other kinds of sources, like `.java`) are +supported in Scala CLI via the `shebang` sub-command (and not otherwise). +However, a shebang header is necessary. An example is given +in [a later section of this guide](#example-shebang-script-with-scala-cli). + +## How to migrate scripts with the old `scala` runner in the shebang header to Scala CLI? + +As described +in [an earlier section of this guide](#how-has-the-passing-of-arguments-been-changed-from-the-old-scala-runner-to-scala-cli), +the way the old `scala` runner handles arguments differs from Scala CLI. + +The old `scala` script accepted arguments with syntax making it easy to use it in a shebang header. +That is, all arguments starting with the second were treated as program args, rather than input sources. +This is in contrast with the Scala CLI default way of handling arguments, where inputs and program arguments have to be +divided by `--`. + +```bash ignore +scala-cli Source1.scala Source2.scala -- programArg1 programArg2 +``` + +To better support shebang scripts, Scala CLI has a dedicated `shebang` sub-command, which handles arguments similarly to +the old `scala` script. + +```bash ignore +scala-cli shebang Source.scala programArg1 programArg2 +``` + +For more concrete examples on how to change the shebang header in your existing scripts, look below. + +### Example shebang script with the Scala `2.13.x` old `scala` runner + +This is how an example shebang script could have looked like for the old `scala` runner with Scala `2.13.x` + +```scala compile title=old-scala-shebang-213.sc +#!/ usr / bin / env scala +println("Args: " + args.mkString(" ")) +``` + +### Example shebang script with the Scala `3.x` old `scala` runner + +This in turn is the Scala `3.x` equivalent for its own old `scala` runner. + +```scala compile title=old-scala-shebang-3.sc +#!/ usr / bin / env scala +@main def main(args: String*): Unit = println("Args: " + args.mkString(" ")) +``` + +### Example shebang script with Scala CLI + +This is an example of how a Scala CLI script with a shebang header looks like. + +```scala compile title=scala-cli-shebang.sc +#!/ usr / bin / env -S scala -cli shebang + println("Args: " + args.mkString(" ")) +``` + +The example above refers `scala-cli`, as per the current default Scala CLI distribution. +If you have Scala CLI installed as `scala`, then that should be changed to the following: + +```scala compile title=scala-cli-as-scala-shebang.sc +#!/ usr / bin / env -S scala shebang +println("Args: " + args.mkString(" ")) +``` + +For more information about the `shebang` sub-command, refer to [the appropriate doc](../commands/shebang.md). +For more details on how to use Scala CLI in shebang scripts, refer to [the relevant guide](../guides/shebang.md). diff --git a/website/docs/reference/scala-command/index.md b/website/docs/reference/scala-command/index.md index 09e13d19c7..a2cfed262e 100644 --- a/website/docs/reference/scala-command/index.md +++ b/website/docs/reference/scala-command/index.md @@ -2,20 +2,27 @@ title: Scala CLI as scala --- - # Scala CLI as implementation for `scala` command -Scala CLI is designed to be a replacement for script that is currently installed as `scala`. Since Scala CLI is feature-packed we do not want to expose all of the features and options to the whole Scala public at the very start. Why is that? - - We want to make sure that the options / commands are stable - - We do not want to overwhelm users with multiple options and commands - - We want to make sure that the commands we add to `scala` are stable so once we commited to supporting given option it may be hard to remove it later +Scala CLI is designed to be a replacement for script that is currently installed as `scala`. Since Scala CLI is +feature-packed we do not want to expose all the features and options to the whole Scala public at the very start. Why is +that? + +- We want to make sure that the options / commands are stable +- We do not want to overwhelm users with multiple options and commands +- We want to make sure that the commands we add to `scala` are stable so once we commited to supporting given option it + may be hard to remove it later + +That is why we built in a mechanism to limit the commands, options, directives in Scala CLI by default. However, it's +still possible to enable all features by explicitly passing the `--power` flag on the command line, or by setting it +globally running: -That is why we built in a mechanism to limit the commands, options, directives in Scala CLI by default. However, it's still possible to enable all features by explicitly passing the `--power` flag on the command line, or by setting it globally running: ```bash ignore scala-cli config power true ``` -To check which options, commands and directives are supported when running Scala CLI with limited functionalities, refer to [options](./cli-options.md), [commands](./commands.md) and [using directives](./directives.md), respectively. +To check which options, commands and directives are supported when running Scala CLI with limited functionalities, refer +to [options](./cli-options.md), [commands](./commands.md) and [using directives](./directives.md), respectively. ## Testing Scala CLI as `scala` @@ -34,4 +41,9 @@ cs setup cs install scala-experimental ← this command will replace the default scala runner ``` -Alternatively, you can rename your `scala-cli` executable or alias it as `scala` +Alternatively, you can rename your `scala-cli` executable or alias it as `scala`. + +## Migrating from the old `scala` runner to Scala CLI + +If you have been using the old `scala` runner and want to migrate to Scala CLI, refer +to [the migration guide](../../guides/old-runner-migration.md).