scala-cli
scala-cli copied to clipboard
Support for initial commands in REPL
Is your feature request related to a problem? Please describe. Support for running initial commands for REPL
Describe the solution you'd like
Adding a flag to specify initial commands. It can be supported in two ways:
- accept string like this: "import Hello.*"
- accept *.sc files which should be executed before opening REPL
I'm not sure the Scala 3 REPL allows to specify initial code like this though (might be the same with the Scala 2 one).
I am reading the documents for ammonite. It’s just that I don’t understand what initial commands are. Do you want scala-cli to support something like magic imports in ammonite ?
You mean something like
scala-cli repl -ic “import Hello.*”
or
scala-cli repl -bo Hello.sc
?
Hi @zmerr, I thinking about similar feature as in SBT.
Yea, It would be great if Scala CLI could be able to accept both -ic “import Hello.*” and scala-cli repl -bo Hello.sc
Hi @lwronski so you mean using those commands for configuring scala-cli to import or open your preferred files in the current execution of repl or some other initial command in the string? Is it what you want me to implement?
Don't know if that's what @lwronski is thinking about, but I think we'd want to use the --predef-code option of Ammonite (which is mentioned on its website). It basically allows to run a bit of code right before the repl session. I guess Scala CLI could accept such code via a flag like… --run-before maybe? or --predef-code like Ammonite?
For *.sc files, maybe we should either read them ourselves, and pass them to Ammonite via --predef-code too, or use Ammonite's --predef option (that accepts paths to *.sc files).
@zmerr If you run scala-cli repl Hello.scala you have access to Hello object
VL-D-0317:scala-demo lwronski$ scala-cli repl Hello.scala
Welcome to Scala 3.1.1 (17.0.1, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
scala> println(Hello.hello)
Hello World
so it would be great if it worked like this:
VL-D-0317:scala-demo lwronski$ scala-cli repl Hello.scala --run-before "import Hello.*"
Welcome to Scala 3.1.1 (17.0.1, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
scala> println(hello)
Hello World
if that's not possible for Scala 2/3 REPL, then we can add this option only for Ammonite REPL
VL-D-0317:scala-demo lwronski$ scala-cli repl Hello.scala --ammonite --run-before "import Hello.*"
Welcome to the Ammonite Repl 2.5.1-6-5fce97fb (Scala 3.0.0 Java 17.0.1)
@ println(hello)
Hello World
@lwronski Awesome. Now I got what it is that you actually want me to do. I am just curious, why are you still adding Hello.scala to the command, when you are already importing Hello.*? Sorry I am new to this.
@lwronski I mean why not this:
scala-cli repl --ammonite --run-before "import Hello.*”
or
scala-cli repl --run-before "import Hello.*”
If you run REPL without the source files, you have REPL without any loaded classes.
scala-cli repl --ammonite --run-before "import Hello.*” - it doesn't make sense, because there is no exists Hello object.
@lwronski thanks. So making it work that way, requires making change to repl as well.
In scala 3 if you write your init script like this
export Hello.*
and you run scala-cli repl InitScript.scala
then in REPL you can already directly access everything that was defined in Hello.
Does this solve our problem?
The only thing I can think of that doesn't work out of the box currently is instant execution of side effects from scripts. So even if I write my init script like this
val xxx = println("Hello")
nothing will be printed until I type xxx in the REPL. But maybe that's actually good that starting a REPL doesn't cause any side effects under the hood?
I've found one limitation of my solution: wildcard exports work correctly with objects but not with packages.
@prolativ @Gedochao I tried to find among issues in dotty a discussion about export not working for packages. I think it really should, if possible, as I think that feature is very useful. Do you perhaps know where to find any potentially existing discussions about exporting top-level package members also, not just object members? This will allow init repl stuff to be used via scala-cli repl --scala-snippet as discussed in #1853
To make things clear: named exports from packages do work - only wildcard exports don't. I assume that's because of complications wildcard imports from packages would bring to incremental compilation. E.g.:
// File1.scala
package pkg1
val x = "a"
// File2.scala
package pkg2
export pkg1.*
Now when this codebase gets compiled and a new file appears:
// File3.scala
package pkg1
val y = "b"
then the compiler would have to figure out that File2.scala has to be recompiled even though none of its dependencies known during the previous compilation has changed. Not to even mention potential cycles of dependencies. In case of objects its much simpler because they're closed - you cannot modify an object without modifying the file in which it's defined or without modifying the sources of its supertypes - but these are already tracked as dependencies transitively
Thanks for the clear explanation @prolativ! So it's a trade-off between being restrictive or risk long compilation times.
I guess my view is that if I introduce wild-card package exports then I want it, even if compilation times get higher. It would be nice though if the compiler or build tool gave me a warning that wildcard exports of packages may trigger a complete re-compilation when new files are added and thus increase compile times.
I would say it's not only about longer compilation times but also about correctness of code, unless we give up incremental compilation and compile everything from scratch each time, which is most likely not what we would like in general.
Aha! That makes sense.
It seems like most of the benefits of an initial script ran in the beginning of repl is already covered by the export syntax, with package wildcards being the problematic edge case.
It'd be optimal for it to be covered by the compiler, but from what @prolativ wrote, it seems that won't happen (at least not soon).
Still, it'd be great to cover this edge case from Scala CLI's side, which would require supporting an initial script ran at the beginning of repl (which is different from --script-snippet, which adds a script to the repl's classpath).
Unfortunately, it seems we lack the time to do it anytime soon.
Community contribution is welcome, though!
Also, this could be a good argument for spending more time on improving the repl itself - if the repl accepted initial scripts, things would become easy.
Thanks for the update @Gedochao ! Yes, ramping up the api of the REPL to make it more versatile would indeed be a nice thing! I think the Scala 3 REPL should have an api that let's it be embedded in an easy way, similar to how the
Scala 2 REPL and also Ammonite for Scala 2 was easy to just instantiate and run things with a simple interpret method call. I had a quick look at the Scala 3 REPL api and it was not obvious how to do this as and I don't understand how to tap into its internal functional State in its current api... So my thumbs up for this!
Closing as duplicate of https://github.com/VirtusLab/scala-cli/issues/604 with more recent discussion
Is this a duplicate of itself :) or did you mean to link to another issue? @tgodzik
I meant this https://github.com/VirtusLab/scala-cli/issues/2185 :sweat_smile:
I'm not sure this is a duplicate of #2185 ; that issue is (also) about the --interactive option etc.
I think being on feature parity with the sbt setting initialCommands is important, as in:
console / initialCommands := """import stuff.*"""
The above works also for Scala 3.
The use case is to prevent tedious re-typing of lot's of imports in every repl session.
Should I open another issue or should we re-open this? I think it is important that this use case is not "forgotten".
Also it might be easier to solve allowing pre-REPL import rather than supporting all the stuff discussed in #2185 so a seperate issue for the import use-case might make sense?
Should I open another issue or should we re-open this? I think it is important that this use case is not "forgotten".
Also it might be easier to solve allowing pre-REPL import rather than supporting all the stuff discussed in https://github.com/VirtusLab/scala-cli/issues/2185 so a seperate issue for the import use-case might make sense?
Agreed, I think a new issue makes sense, given the number of different things that were discussed here and in #2185.
OK I'll make a new issue soon and link to the other issues.