Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SIP-46 - Use Scala CLI to implement the 'scala' command #46

Merged
merged 9 commits into from
Oct 21, 2022
167 changes: 167 additions & 0 deletions content/scala-cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
---
layout: sip
permalink: /sips/:title.html
stage: implementation
status: waiting-for-implementation
title: SIP-46 - Scala CLI as default Scala command
---

**By: Krzysztof Romanowski and Scala CLI team**

## History

| Date | Version |
|---------------|--------------------|
| July 15th 2022 | Initial Draft |

## Summary

We propose to replace current script that is installed as `scala` with Scala CLI - a batteries included tool to interact with Scala. Scala CLI brings all the features that the commands above provide and expand them with incremental compilation, dependency management, packaging and much more.

Even though Scala CLI could replace `scaladoc` and `scalac` commands as well for now, we do not propose to replace them.


## Motivation

The current default `scala` script is quite limited since it can only start repl or run pre-compile Scala code.

The current script are lacking basic features such as support for resolving dependencies, incremental compilation or support for outputs other than JVM. This forces any user that wants to do anything more than just basic things to learn and use SBT, Mill or an other build tool and that adds to the complexity of learning Scala.

We observe that the current state of tooling in Scala is limiting creativity, with quite a high cost to create e.g. an application or a script with some dependencies that target Node.js. Many Scala developers are not choosing Scala for their personal projects, scripts, or small applications and we believe that the complexity of setting up a build tool is one of the reasons.
Copy link
Member

@ckipp01 ckipp01 Jul 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE: Not part of the SIP committee, just a passerby with a comment.

We observe that the current state of tooling in Scala is limiting creativity ... we believe that the complexity of setting up a build tool is one of the reasons

Firstly, I really enjoy scala-cli, and I believe it's a much needed tool. I'm really excited to see this here. However, I also think we should try to avoid hyperbole here. This is listed as one of the main points up here in motivation with the crux of the argument being what I quoted up above.

Here is the minimal build tool setup in sbt including a dependency

ThisBuild / scalaVersion := "3.1.3"

lazy val myproject = project
  .settings(
    libraryDependencies += "com.lihaoyi" %% "pprint" % "0.7.3"
  )

A single sbt command can also get you a fresh hello project that a user can just do sbt run and see hello. The same exists in Mill as well, which is arguably even easier.

Here is the same with scala-cli

//> using scala "3.1.1"
//> using lib "com.lihaoyi::pprint:0.7.3"

Is the difference above really what is limiting creativity in Scala? Is learning the basic sbt structure somehow more complex than learning using directives in scala-cli?

You do mention some good points here:

with quite a high cost to create e.g. an application or a script with some dependencies that target Node.js

No doubt cross platform support is confusing in build tools, but seeing that this is a giant change in the ecoystem by changing the way someone first interacts with the language I think the SIP should include a couple things.

  1. Why was this route chosen rather than improving some of these pain points in the existing tooling?
  2. How is learning new concepts introduced by scala-cli such as learning directives and BSP easier to digest than other concepts in tools like sbt or Mill which you mention as a roadblock to creativity.

Mainly because investing time into a brand new tool is also an extremely high cost. Especially in a tooling ecosystem already starved of maintainers and contributors.

None of this means we shouldn't do it, but it just means we should be crystal clear about the why, and seeing that this is listed as one of the main motivations of this SIP I'd expect the questions up above also to be crystal clear in the document, and after reading this SIP they weren't answered for me.

Copy link

@bjornregnell bjornregnell Jul 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ckipp01 I can imagine that we in some future could have an official list of curated libs so that we could write something like:

//> using scala "3.1.1"
//> using pprint "0.7.3"

and that level of simplicity would be really nice from a beginner perspective, and this SIP is taking a big step towards that level of quality UX. (or is the new cool buzzword rather DX now 😄 ) To avoid strange % and %% and : and :: that learners get intimidated by...

Copy link
Member

@ckipp01 ckipp01 Jul 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid strange % and %% and : and :: that learners get intimidated by...

O for sure, but again, this doesn't address the main question I had about the effort going into a new tool, vs addressing these pain points in the existing tools. Take the example you have up above, and there actually are discussions about them both in Mill and in sbt. We shy away from talking about it, but in Scala we have a handful of tools that almost all have single maintainers, and sometimes barely that. A lot of pains points we feel could be addressed given focus and people time. Imagine adding up all the hours of various devs that have gone into making scala-cli, and imagine putting all those hours towards exiting issues and problems. What would have a greater impact on the ecosystem?

Again, I want to reiterate that I'm not saying this necessarily as a reason against scala-cli, I'm happily using scala-cli, but it's just a big glaring question mark still, is all the effort going into scala-cli (which also forces other tooling to put in effort to support this new tool) a net positive vs if all that effort was put into existing problems and tools. Maybe the answer is yes, starting from a clean slate offers us the greatest impact to make a change for the better in welcoming newcomers, addressing exiting problems, and pushing the boundaries of the existing tooling ecosystem. If that's the case, then I'm 110% behind it. Sign me up. For me personally, as someone who spends a lot of my time trying to help maintain other tools, answering the above question is most what I'm curious about.*

If this was just a project some person or company was working on because it was fun, or something they deemed worth it for them, cool. But I'm harping on the above so much because what we're proposing is a fundamental change to how someone is introduced to Scala, both from the command line and the editor. It's a big deal.


*I want to recognize that this isn't an easy question, or a new one. Balancing older stable tools with pain points and addressing them vs pushing the boundaries with new shiny ideas that don't fit within the confines of the existing tools. However I believe this just justifies putting the decision and answer to this question right at the forefront to show that it's really been discussed and thought about.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or is the new cool buzzword rather DX now 😄

😆 I'm so happy to see this being used here.

Copy link
Contributor

@julienrf julienrf Aug 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to emphasize this point with a concrete example of “build definition” for Scala CLI:

https://github.com/VirtusLab/typed-frames/blob/5b6ca450d9c14a0c668283f00e1847298a9af050/publish-conf.scala#L1-L8

I don’t think this is significantly better or simpler than the equivalent with sbt, gradle, mill, etc. It just looks the same: you supply the information to put in the pom.xml that will ultimately be published.

So, my suggestion would be to rephrase the sentence that raised this discussion to position Scala CLI differently. I don’t think it improves much the landscape of build tools, but I think it improves significantly the current Scala interpreter (the one we get with the scala command line tool) because that one can’t be configured with directives.

Copy link

@sideeffffect sideeffffect Aug 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A thought from a humble non-affiliated Scala user:

I don’t think it improves much the landscape of build tools, but I think it improves significantly the current Scala interpreter (the one we get with the scala command line tool) because that one can’t be configured with directives.

I feel that an analogous explanation might be helpful here why/how it's better than Ammonite, which is the incumbent featureful configurable Scala interpreter.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know, it lacks some features, see e.g. com-lihaoyi/Ammonite#1093

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ckipp01 I can imagine that we in some future could have an official list of curated libs so that we could write something like:

//> using scala "3.1.1"
//> using pprint "0.7.3"

Related: https://contributors.scala-lang.org/t/why-doesnt-scala-have-library-listing/5696

Copy link

@sideeffffect sideeffffect Sep 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May I humbly suggest to extend the section as

Why decided to work on Scala CLI rather then improve existing tools like sbt, Mill or Ammonite?

For similar reasons as with sbt or Mill, Ammonite is an already existing tool that shares some similarities with scala-cli. I'm suggesting this, because I think it would be helpful to the wider Scala community to write down the reasons why it was better to start from scratch instead of building on top of Ammonite. Thank you :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the difference above really what is limiting creativity in Scala? Is learning the basic sbt structure somehow more complex than learning using directives in scala-cli?

Since it is very much a first expression I believe it matters, yes. It's similar to arguing that static public void main(args: String[]) is of so much of an issue, which is true, but since it's the first thing a newcomer sees it matters.


With this proposal our main goal is to turn Scala into a language with "batteries included" that will also respect the community-first aspect of our ecosystem.

### Why decided to work on Scala CLI rather then improve existing tools like sbt or Mill?

Firstly, Scala CLI is in no way an actual replacement for SBT or Mill - nor was it ever meant to be. We do not call it a build tool, even though it does share some similarities with build tools. It doesn't aim at supporting multi-module
projects, nor to be extended via a task system. The main advantages of SBT and Mill: multi-module support and plugin ecosystem in the use cases for Scala CLI and scala command can often be disadvantages as it affects performance: configuration needs to be compiled, plugins resolved etc.

Mill and SBT uses turing complete configuration for build so the complexity of build scripts in theory is unlimited. Scala CLI is configuration-only and that limits the complexity what put a hard cap how complex Scala CLI builds can be.

In our opinion, `scala` command should be first and foremost a command line tool. Requirements for a certain project structure or presence configuration files limit SBT and Mill usability certain use cases related to command line.

One of the main requirements for the new `scala` commands was speed, flexibility and focus on command-line use cases. Initially, we were considering improving SBT or Mill as well as building Scala CLI on top one. We have quickly realized that getting Mill or SBT to reply within Milliseconds (for cases where no hard work like compilation is require) would be pretty much out of reach. Mill and SBT's codebases are too big to compile them to native image using GraalVM, not to mention problems with dynamic loading and reflection. Adding flexibility when in comes to input sources (e.g. support for Gists) and making the tool that can accept most of the configuration using simple command-line parameters would involve writhing a lot of glue code. That is why we decided to build the tool from scratch based on existing components like coursier, bloop or scalafmt.

## Proposed solution

We propose to gradually replace the current `scala`, `scalac` and `scaladoc` commands by single `scala` command that under the hood will be `scala-cli`. We could also add wrapper scripts for `scalac` and `scaladoc` that will mimic the functionality that will use `scala-cli` under the hood.

The complete set of `scala-cli` features can be found in [its documentation](https://scala-cli.virtuslab.org/docs/overview).

Scala CLI brings many features like testing, packaging, exporting to sbt / Mill or upcoming support for publishing micro-libraries. Initially, we may want to limit the set of features available in the `scala` command by default. Scala CLI is a relatively new project and we should battle-proof some of its features before we commit to support them as part of the offical `scala` command.

Scala CLI offers [multiple native ways to be installed](https://scala-cli.virtuslab.org/install#advanced-installation) so most users should find a suitable method. We would like these packages to become the default `scala` package in most repositories, often replacing existing `scala` packages.

### High-level overview

Let us show a few examples where adopting Scala CLI as `scala` command would be a significant improvement ofer current scripts. For this, we have assumed a minial set of features. Each additional Scala CLI feature included, such as `package`, would add more and more use cases.

**Using REPL with a 3rd-party dependency**

Currently, to start a Scala REPL with a dependency on the class path, users need to resolve this dependency with all its transitive dependencies (coursier can help here) and pass those to the `scala` command using the `--cp` option. Alternatively, one can create an sbt project including a single dependency and use the `sbt console` task. Ammonite gives a better experience with its magic imports.

With Scala CLI, starting a REPL with a given dependency is as simple as running:

```
scala-cli repl --dep com.lihaoyi::os-lib:0.7.8
```

Compared to Ammonite, default Scala REPLs provided by Scala 2 and 3 - that Scala CLI uses by default - are somewhat limited. However, Scala CLI also offers to start Ammonite instead of the default Scala REPL, by passing `--ammonite` (or `--amm`) option to `scala-cli repl`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it isn't appropriate to include --ammonite in the default scala runner. If we do, it means we commit to supporting it forever, and that means supporting Ammonite itself forever. This is a significant weight.

In the context of Scala CLI, the REPL is not so limited anymore. In particular, it can use dependencies specified through Maven coordinates. So I don't think there is anything fundamental that we need Ammonite for.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a good point. That is why we were considering making some of the options non-stable so we can drop them at any point, and ammonite may be such an opinion.


Additionally, `scala-cli repl` can also put code from given files / directories / snippets on the class path by just providing their locations as arguments. Running `scala-cli repl foo.scala baz` will compile code from `foo.scala` and the `baz` directory, and put their classes on the REPL class path (including their dependencies, scalac options etc. defined within those files).

Compilation (and running scaladoc as well) benefit in a similar way from the ability to manage dependencies.

** Providing reproductions of bugs **

Currently, when reporting a bug in the compiler (or any other Scala-related) repository, users need to provide depencencies, compiler options etc. in comments, create a repository containing a projet with a Mill / sbt configuration to reproduce. In general, testing the reporoduction or working on further minization is not straightworwad.

"Using directives", provided by Scala CLI give the ablity to include the whole configuration in single file, for example:

```scala
//> using platform "native"
//> using "com.lihaoyi::os-lib:0.7.8"
//> using options "-Xfatal-warnings"

def foo = println("<here comes the buggy warning with Scala Native and os-lib>")
```

The snippet above when run with Scala CLI without any configuration provided will use Scala Native, resolve and include `os-lib` and provide `-Xfatal-warnings` to the compiler. Even things such as the runtime JVM version can be configured with using directives.

Moreover, Scala CLI provides the ability to run GitHub gists (including multi-file ones), and more.

** Watch mode **

When working on a piece of code, it is often useful to have it compiled/run everytime the file is changed, and build tools offer a watch mode for that. This is how most people are using watch mode through a build tool. Scala CLI offers a watch mode for most of its commands (by using `--watch` / `-w` flags).


### Specification

In order to be able to expand the functionality of Scala CLI and yet use the same core to power the `scala` command, we propose to include both `scala` and `scala-cli` commands in the installation package. Scala CLI already has a feature to limit accessible sub-commands based the binary name (all sub-commands in `scala-cli`, and a curated list in `scala`). Later, we can include more and more features from `scala-cli` into `scala`.

The sub-commands necessary to include in the `scala` to match the functionalities of current commands:
- `compile`
- `run`
- `repl`
- `doc`

On top of that, we think that the following user-facing sub-commands should also be included:
- `clean` - to rebuild project from start without any cached steps
- `setup-ide` - to control the setup of BSP for IDE integration
- `doctor` - to analyze if everything is installed properly

We also suggest to include additional sub-commands by default:
- `fmt` - to format the code using scalafmt
- `test` - to run tests included in the code
- `package` - to package the code into various package formats: JAR, "fat" be, executable be or even native application or docker image
- `shebang` - a command useful for scripting, designed to be included in the "shebang" section of scripts
- `export` - transform current project to sbt / Mill project using the same settings as provided. Useful to evolve prototypes into bigger projects

Each of these commands expands what the current scripts offer and can be discussed separately. We can even open a dedicated SIP for each of them.

Beyond that, `scala-cli` offers multiple sub-commands needed to manage itself (e.g. `update`) or its components (e.g. the Bloop server). In most cases,
these are not user-facing, but still handy. We can elaborate in more detail on what those commands are and why we need them, if necessary.

Scala CLI can also be configured with ["using directives"](https://scala-cli.virtuslab.org/docs/guides/using-directives) - a comment-based configuration syntax that should be placed at the top of Scala files. This allows for self-containing examples within one file since most of the configuration can be provided either from the command line or via using directives (command line has precedence). This is a game changer for use cases like scripting, reproduction, or within the academic scope.

We have described the motivation, syntax and implementation basis in the [dedicated pre-SIP](https://contributors.scala-lang.org/t/pre-sip-using-directives/5700). Currently, we recommend to write using directives as comments, so making them part of the language specification is not necessary at this stage. Moreover, the new `scala` command could ignore using directives in the initial version, however we strongly suggest to include comment-based using directives from the start.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the scala command ignores the using directives, then it provides basically no value over the current command. Therefore, I don't see ignoring directives in an initial version as a viable alternative.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the same topic, I will repeat here, in the context of the SIP process, an opinion I have already expressed elsewhere. I believe using directives must be integrated into the language, and not offered as comments.

The reason boils down to: using directives specify the semantics of the program (through Scala version and compiler options at the least, and I would argue through dependencies as well). These things are non-optional. They must be taken into account. Putting them in comments goes against all principles about what comments are.

I know that tooling people don't want to read this, because it means they need to support it. But that is not different from anything else that goes through the SIP process. Moreover, as pointed out above, they will have to deal with those "comments" anyway to respect the program semantics. So I consider that objection as moot.


#### Commands, options and directives

We have generated a complete lists of supported [commands](https://github.com/romanowski/scala-cli/blob/6b7e9614078070ce8ff6cbcb0635b78901228749/website/src/pages/scala-command/commands.md), [CLI options](https://github.com/romanowski/scala-cli/blob/6b7e9614078070ce8ff6cbcb0635b78901228749/website/src/pages/scala-command/cli-options.md) and [directives](https://github.com/romanowski/scala-cli/blob/6b7e9614078070ce8ff6cbcb0635b78901228749/website/src/pages/scala-command/directives.md) that we propose for new `scala` command. Lists contain many options and commands that are marked as `experimental` and/or `internal` and as such, we could change them at any point.

The lists was generated automatically and starting from next release of Scala CLI such documentation will be included on our website. Using that lists, it will be easy to track and spot any changes in exposed APIs.

### Compatibility
julienrf marked this conversation as resolved.
Show resolved Hide resolved

Adopting Scala CLI as the new `scala` command, as is, will change some of the behaviour of today's scripts. Some examples:

- Scala CLI recognizes tests based on the extension used (`*.test.scala`) so running `scala compile a.scala a.test.scala` will only compile `a.scala`
- Scala CLI has its own versioning scheme, that is not related to the Scala compiler. Default version used may dynamically change when new Scala version is released. Similarly to Scala 3, we intend for Scala CLI to be backward compatible and this should help mitigate this risk.
- By default, Scala CLI manages its own dependencies (e.g. scalac, zinc, Bloop) and resolves them lazily. This means that the first run of Scala CLI resolves quite some dependencies. Moreover, Scala CLI periodically checks for updates, new defaults accessing online resources (but it is not required to work, so Scala CLI can work in offline environment once setup)
- Scala CLI can also be configured via using directives. Command line options have precedence over using directives, however using directives override defaults. Compiling a file starting with `//> using scala 2.13.8`, without providing a Scala version on the command line, will result in using `2.13.8` rather than the default Scala version. We consider this a feature. However, technically, this is a breaking change.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it surprising that the SIP describes the command-line arguments as the prime means of configuring it, and using directives as a "fallback", secondary thing. It should be the other way around, IMO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scala CLI is cmd-first, and that is why cmd args take precedence. For us, a situation when a user tries to compile code providing a given version of Scala and another is picked would be confusing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I wasn't clear before. Command-line args should definitely take precedence over file configuration. This is a universal good practice among all software.

But using clauses should be presented as the normal way of specifying options. Command-line args should only be used to punctually override the configured using clauses, but not as the regular way of doing things.


### Other concerns

Scala CLI brings [using directives](https://scala-cli.virtuslab.org/docs/guides/using-directives) and [conventions to mark the test files](https://scala-cli.virtuslab.org/docs/commands/test#test-sources). We are not sure if both can be accepted as a part of this SIP or we should have seperate SIPs for both (we have opened a [pre-SIP for using directives](https://contributors.scala-lang.org/t/pre-sip-using-directives/5700/15))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this SIP should at least specify the using directives that are recognized and applied by the commands available in scala, and that affect program semantics. So that includes using scala, using options, probably the platforms, etc.

Likewise, if we do introduce the test command, then we need to decide about the test files convention. (I am a bit worried about that one regarding the .test.scala since, as you point out above, it flat-out disregards files provided on the command-line of scala compile.)


Scala CLI is an ambitious project and may seem hard to maintain in the long-run.


### Open questions

The main open question for this proposal is wich commands/features should be included by default in the `scala` command. Another aspect is the release cadence: should the new `scala` command follow the current release cadence for Scala CLI (every 2 weeks) or stick to Scala one (every 6 weeks)?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The main open question for this proposal is wich commands/features should be included by default in the `scala` command. Another aspect is the release cadence: should the new `scala` command follow the current release cadence for Scala CLI (every 2 weeks) or stick to Scala one (every 6 weeks)?
The main open question for this proposal is which commands/features should be included by default in the `scala` command. Another aspect is the release cadence: should the new `scala` command follow the current release cadence for Scala CLI (every 2 weeks) or stick to Scala one (every 6 weeks)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that Scala CLI will dynamically resolve various Scala versions, I don't see the point in tying its release schedule to that of dotc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am also all for the independent release scheme but @julienrf and others shared some concerns about this, and that is why I have included it as an open question.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, the setup instructions tell you to run scala -version to test your setup:

Screenshot from 2022-07-20 13-38-30

What do we want scala -version to return when scala is implemented via scala-cli? I thought it could make sense to build a scala command with every release of Scala, and which would default to the Scala version of that release.

Otherwise, we can decide that the version of scala has nothing to do with an actual version of Scala, and in that case, we should document it explicitly.

Copy link
Member

@sjrd sjrd Aug 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, scala -version should show the version of Scala that will be used if I use scala (i.e., scala repl) or scala compile in the current directory (which means taking using clauses into account). The version of the launcher is irrelevant in 99% of use cases, and probably 100% of beginner use cases.

For the Python lovers, compare with py --version/py -3 --version which show "Python 3.10.5" and py -2 --version which shows "Python 2.7.18": I get the version of Python that will be used if I run py/py -3 or py -2. The version of py itself is irrelevant.

Copy link
Contributor

@julienrf julienrf Aug 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After a discussion with Sébastien, here is a suggestion about this point: when someone invokes scala -version, simply prints both the version of the runner (ie, scala-cli), and the current version of Scala. The current version of Scala would depend on the working directory (e.g., if there is a Scala project that configures a specific Scala version with a “using” directive, that version should be printed).

Example:

$ scala -version .
Scala code runner version: 1.2.3
Scala version (set in ./my-program.scala:2): 3.1.3

Or:

$ scala -version
Scala code runner version: 1.2.3
Default Scala version: 3.2.0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I created an issue for it: VirtusLab/scala-cli#1250

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After a discussion with Sébastien, here is a suggestion about this point: when someone invokes scala -version, simply prints both the version of the runner (ie, scala-cli), and the current version of Scala. The current version of Scala would depend on the working directory (e.g., if there is a Scala project that configures a specific Scala version with a “using” directive, that version should be printed).

Example:

$ scala -version .
Scala code runner version: 1.2.3
Scala version (set in ./my-program.scala:2): 3.1.3

Or:

$ scala -version
Scala code runner version: 1.2.3
Default Scala version: 3.2.0

What is the motivation for mixing up the concerns of the version of scala-cli and "inspecting" a project/file? I suspect having multiple versions displayed in the output would create some confusion for new users.

It would be useful for the default scala version (--scala-version option) to be displayed in the output of --help for the relevant subcommands (e.g., run, compile, etc...). Currently, there's no default shown.

$> scala-cli compile --help | grep scala-version
  -S, --scala, --scala-version version           Set the Scala version

However, a useful error message is displayed if an unsupported value is provided.

$> scala-cli run --scala-version 7 Example.scala
[error]  Cannot find matching Scala version for '7'
You can only choose one of the 3.x, 2.13.x, and 2.12.x. versions.
The latest supported stable versions are 3.1.3, 2.13.8, 2.12.16.
In addition, you can request compilation with the last nightly versions of Scala,
by passing the 2.nightly, 2.12.nightly, 2.13.nightly, or 3.nightly arguments.
Specific Scala 2 or Scala 3 nightly versions are also accepted.

Ideally, the defaults of other command line flags, such as --jvm, would be communicated in the output of --help as well.

I agree with your suggestion that "inspecting" a project would be a welcomed addition. Perhaps this use case would be better as a new subcommand that could provide more information about a project/file. For example, the configured scala version, the --scalac-options used, the resolved dependencies, or a list of main classes. Having an "inspect" functionality decoupled from --version and captured in a subcommand would also enable adding more fine grained information about a project/file over time. Overloading --version with this info would probably not age well.

Currently, I find scala-cli sometimes a little tricky to debug when I've configured it incorrectly (e.g., main class), or for cases where it's unclear what default values are being used by scala-cli. It could be useful to get feedback from the community to evaluate if an "inspect" functionality could improve the overall user experience.

Overall, I'm finding scala-cli to be a very positive addition to the scala ecosystem.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the motivation for mixing up the concerns of the version of scala-cli and "inspecting" a project/file?

I guess someone who installed Scala would be very likely to try scala -version to know which version of Scala is installed. But since scala will be a runner able to run any version of Scala, it makes sense to also show to the user the version of the CLI that is installed.

A similar situation is when someone starts a REPL session. We show both the JDK version and the Scala version because both are useful.


## Alternatives

Scala CLI has many alternatives. The most obvious ones are sbt, Mill, or other build tools. However, these are more complicated than Scala CLI, and what is more important they are not designed as command-line first tools. Ammonite, is another alternative, however it covers only part of the Scala CLI features (REPL and scripting), and lacks many of the Scala CLI features (incremental compilation, Scala version selection, support for Scala.js and Scala Native, just to name a few).

## Related work

- [Scala CLI website](https://scala-cli.virtuslab.org/) and [road map](https://github.com/VirtusLab/scala-cli/discussions/1101)
- [Pre-SIP](https://contributors.scala-lang.org/t/pre-sip-scala-cli-as-new-scala-command/5628/22)
- [leiningen](https://leiningen.org/) - a similar tool from Closure, but more configuration-oriented

## FAQ

This section will probably initially be empty. As discussions on the proposal progress, it is likely that some questions will come repeatedly. They should be listed here, with appropriate answers.