Skip to content

Conversation

@lihaoyi
Copy link
Contributor

@lihaoyi lihaoyi commented Oct 3, 2025

This PR is a proof-of-concept implementation porting over the Ammonite import $ivy functionality to the Scala REPL, using a :dep syntax, with an error message on the Scala-CLI using dep syntax pointing at :dep. Once this lands, along with other related PRs (#24127, #23849) we can probably deprecate Ammonite and refer people to the main Scala REPL since it'll have acquired all the important features

Tested manually:

Screenshot 2025-11-11 at 5 34 32 PM

Both io.get-coursier:interface and org.virtuslab:using_directives are zero-dependency Java libraries, and so can be used directly without worrying about binary compatibility. Both libraries are widely used in the Scala ecosystem (SBT, Mill, ScalaCLI, Bazel, ...) and should be pretty trustworthy and reliable

@lihaoyi
Copy link
Contributor Author

lihaoyi commented Oct 3, 2025

The failure looks like a network flake

@hamzaremmal
Copy link
Member

hamzaremmal commented Oct 4, 2025

I think we should extract the repl to be its own artifact before accepting this change. @Gedochao lets add splitting the repl from the compiler to next week's core.

@Gedochao Gedochao added the stat:needs decision Some aspects of this issue need a decision from the maintainance team. label Oct 8, 2025
@Gedochao Gedochao requested review from Gedochao and tgodzik October 8, 2025 08:54
@SethTisue
Copy link
Member

It makes a great deal of architectural sense for the REPL to be its own artifact. The REPL is conceptually separate, and most consumers of the compiler don't consume the REPL. (Making the separation in Scala 2 was a long term goal of @adriaanm's that he did a great deal of work on, but we just never got it over the finish line.)

@Gedochao Gedochao removed the stat:needs decision Some aspects of this issue need a decision from the maintainance team. label Oct 8, 2025
@Gedochao
Copy link
Contributor

Gedochao commented Oct 8, 2025

We will explore making REPL its own artifact, in which case the approach from this PR could work.
It's also in the works whether we'd want to do it in 3.8 (for //> using dep to be available in the new 3.9 LTS later), or should this feature wait for 3.10.
@lihaoyi this may take us some time, we'll comment on this PR once a strategy gets established.
cc @WojciechMazur

@Gedochao Gedochao added the stat:needs decision Some aspects of this issue need a decision from the maintainance team. label Oct 8, 2025
@lihaoyi
Copy link
Contributor Author

lihaoyi commented Oct 8, 2025

Since this isn't a language feature, presumably we can introduce it anytime? It's only for interactive use so there's no backwards compatibility concerns

@Gedochao
Copy link
Contributor

Gedochao commented Oct 9, 2025

Since this isn't a language feature, presumably we can introduce it anytime? It's only for interactive use so there's no backwards compatibility concerns

Presumably, yes, but given that it's a rather big feature for the REPL, it would fit in a new minor better.
We've yet to decide how to go about this.

@bishabosha
Copy link
Member

Splitting the classpath into a separate jar probably is a minor release requirement - e.g. tooling like Scala CLI --with-compiler would need to be updated

@hamzaremmal
Copy link
Member

@lihaoyi this too will require a rebase now.

case NonFatal(e) => Nil // If parsing fails, fall back to empty list

/** Resolve dependencies using Coursier Interface and return the classpath as a list of File objects */
def resolveDependencies(dependencies: List[(String, String, String)]): Either[String, List[File]] =
Copy link
Member

Choose a reason for hiding this comment

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

This can be improved in the future by supporting:

//> using repository ...

https://scala-cli.virtuslab.org/docs/reference/directives#repository

@lihaoyi
Copy link
Contributor Author

lihaoyi commented Nov 1, 2025

This will need to wait until bin/scala is wired up before we can rebase and test it

@tgodzik tgodzik removed the stat:needs decision Some aspects of this issue need a decision from the maintainance team. label Nov 3, 2025
@bishabosha
Copy link
Member

@lihaoyi you should be able to test by local publishing the binaries, i.e. don’t need to wait for bin/scala to work

@lihaoyi
Copy link
Contributor Author

lihaoyi commented Nov 11, 2025

Testing manually via

lihaoyi scala3$ sbt --client scala3-compiler-bootstrapped/publishLocalBin
sbt --client scala3-library-bootstrapped/publishLocalBin
sbt --client tasty-core-bootstrapped/publishLocalBin
sbt --client scala3-repl/publishLocalBin
java -cp $(cs fetch -p org.scala-lang:scala3-repl_3:3.8.0-RC1-bin-SNAPSHOT) dotty.tools.repl.Main -cp $(cs fetch -p org.scala-lang:scala3-repl_3:3.8.0-RC1-bin-SNAPSHOT)                                        
[info] entering *experimental* thin client - BEEP WHIRR
[info] terminate the server with `shutdown`
> scala3-compiler-bootstrapped/publishLocalBin
[info] Wrote /Users/lihaoyi/Github/scala3/compiler/../out/bootstrap/scala3-compiler-bootstrapped/scala-3.8.0-RC1-bin-SNAPSHOT-nonbootstrapped/scala3-compiler_3-3.8.0-RC1-bin-SNAPSHOT.pom
[info] :: delivering :: org.scala-lang#scala3-compiler_3;3.8.0-RC1-bin-SNAPSHOT :: 3.8.0-RC1-bin-SNAPSHOT :: integration :: Tue Nov 11 12:18:06 CST 2025
[info] 	delivering ivy file to /Users/lihaoyi/Github/scala3/out/bootstrap/scala3-compiler-bootstrapped/scala-3.8.0-RC1-bin-SNAPSHOT-nonbootstrapped/ivy-3.8.0-RC1-bin-SNAPSHOT.xml
[info] 	published scala3-compiler_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/scala3-compiler_3/3.8.0-RC1-bin-SNAPSHOT/jars/scala3-compiler_3.jar
[info] 	published scala3-compiler_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/scala3-compiler_3/3.8.0-RC1-bin-SNAPSHOT/srcs/scala3-compiler_3-sources.jar
[info] 	published scala3-compiler_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/scala3-compiler_3/3.8.0-RC1-bin-SNAPSHOT/poms/scala3-compiler_3.pom
[info] 	published scala3-compiler_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/scala3-compiler_3/3.8.0-RC1-bin-SNAPSHOT/docs/scala3-compiler_3-javadoc.jar
[info] 	published ivy to /Users/lihaoyi/.ivy2/local/org.scala-lang/scala3-compiler_3/3.8.0-RC1-bin-SNAPSHOT/ivys/ivy.xml
[success] Total time: 1 s, completed Nov 11, 2025, 12:18:06 PM
[info] entering *experimental* thin client - BEEP WHIRR
[info] terminate the server with `shutdown`
> scala3-library-bootstrapped/publishLocalBin
[info] Wrote /Users/lihaoyi/Github/scala3/library/../out/bootstrap/scala3-library-bootstrapped/scala-3.8.0-RC1-bin-SNAPSHOT-nonbootstrapped/scala3-library_3-3.8.0-RC1-bin-SNAPSHOT.pom
[info] :: delivering :: org.scala-lang#scala3-library_3;3.8.0-RC1-bin-SNAPSHOT :: 3.8.0-RC1-bin-SNAPSHOT :: integration :: Tue Nov 11 12:18:06 CST 2025
[info] 	delivering ivy file to /Users/lihaoyi/Github/scala3/out/bootstrap/scala3-library-bootstrapped/scala-3.8.0-RC1-bin-SNAPSHOT-nonbootstrapped/ivy-3.8.0-RC1-bin-SNAPSHOT.xml
[info] 	published scala3-library_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/scala3-library_3/3.8.0-RC1-bin-SNAPSHOT/jars/scala3-library_3.jar
[info] 	published scala3-library_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/scala3-library_3/3.8.0-RC1-bin-SNAPSHOT/srcs/scala3-library_3-sources.jar
[info] 	published scala3-library_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/scala3-library_3/3.8.0-RC1-bin-SNAPSHOT/poms/scala3-library_3.pom
[info] 	published scala3-library_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/scala3-library_3/3.8.0-RC1-bin-SNAPSHOT/docs/scala3-library_3-javadoc.jar
[info] 	published ivy to /Users/lihaoyi/.ivy2/local/org.scala-lang/scala3-library_3/3.8.0-RC1-bin-SNAPSHOT/ivys/ivy.xml
[success] Total time: 0 s, completed Nov 11, 2025, 12:18:06 PM
[info] entering *experimental* thin client - BEEP WHIRR
[info] terminate the server with `shutdown`
> tasty-core-bootstrapped/publishLocalBin
[info] Wrote /Users/lihaoyi/Github/scala3/tasty/../out/bootstrap/tasty-core-bootstrapped/scala-3.8.0-RC1-bin-SNAPSHOT-nonbootstrapped/tasty-core_3-3.8.0-RC1-bin-SNAPSHOT.pom
[info] :: delivering :: org.scala-lang#tasty-core_3;3.8.0-RC1-bin-SNAPSHOT :: 3.8.0-RC1-bin-SNAPSHOT :: integration :: Tue Nov 11 12:18:07 CST 2025
[info] 	delivering ivy file to /Users/lihaoyi/Github/scala3/out/bootstrap/tasty-core-bootstrapped/scala-3.8.0-RC1-bin-SNAPSHOT-nonbootstrapped/ivy-3.8.0-RC1-bin-SNAPSHOT.xml
[info] 	published tasty-core_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/tasty-core_3/3.8.0-RC1-bin-SNAPSHOT/jars/tasty-core_3.jar
[info] 	published tasty-core_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/tasty-core_3/3.8.0-RC1-bin-SNAPSHOT/srcs/tasty-core_3-sources.jar
[info] 	published tasty-core_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/tasty-core_3/3.8.0-RC1-bin-SNAPSHOT/poms/tasty-core_3.pom
[info] 	published tasty-core_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/tasty-core_3/3.8.0-RC1-bin-SNAPSHOT/docs/tasty-core_3-javadoc.jar
[info] 	published ivy to /Users/lihaoyi/.ivy2/local/org.scala-lang/tasty-core_3/3.8.0-RC1-bin-SNAPSHOT/ivys/ivy.xml
[success] Total time: 0 s, completed Nov 11, 2025, 12:18:07 PM
[info] entering *experimental* thin client - BEEP WHIRR
[info] terminate the server with `shutdown`
> scala3-repl/publishLocalBin
[info] Wrote /Users/lihaoyi/Github/scala3/repl/target/scala-3.7.4/scala3-repl_3-3.8.0-RC1-bin-SNAPSHOT.pom
[info] :: delivering :: org.scala-lang#scala3-repl_3;3.8.0-RC1-bin-SNAPSHOT :: 3.8.0-RC1-bin-SNAPSHOT :: integration :: Tue Nov 11 12:18:09 CST 2025
[info] 	delivering ivy file to /Users/lihaoyi/Github/scala3/repl/target/scala-3.7.4/ivy-3.8.0-RC1-bin-SNAPSHOT.xml
[info] 	published scala3-repl_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/scala3-repl_3/3.8.0-RC1-bin-SNAPSHOT/jars/scala3-repl_3.jar
[info] 	published scala3-repl_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/scala3-repl_3/3.8.0-RC1-bin-SNAPSHOT/srcs/scala3-repl_3-sources.jar
[info] 	published scala3-repl_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/scala3-repl_3/3.8.0-RC1-bin-SNAPSHOT/poms/scala3-repl_3.pom
[info] 	published scala3-repl_3 to /Users/lihaoyi/.ivy2/local/org.scala-lang/scala3-repl_3/3.8.0-RC1-bin-SNAPSHOT/docs/scala3-repl_3-javadoc.jar
[info] 	published ivy to /Users/lihaoyi/.ivy2/local/org.scala-lang/scala3-repl_3/3.8.0-RC1-bin-SNAPSHOT/ivys/ivy.xml
[success] Total time: 2 s, completed Nov 11, 2025, 12:18:09 PM
Resolving package/object name conflict in favor of package scala.caps. The object will be inaccessible.
Welcome to Scala 3.8.0-RC1-bin-SNAPSHOT-git-1f90f81 (21.0.8, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
                                                                                                                          
scala> //> using dep "com.lihaoyi::scalatags:0.13.1"
Resolved 1 dependencies (5 JARs)
                                                                                                                          
scala> //> using dep "com.lihaoyi::scalatags:0.13.1"
                                                                                                                          
scala> import scala.quoted.*
       def lineImpl(using Quotes): Expr[Int] = {
         val sourceFile = quotes.reflect.Position.ofMacroExpansion.sourceFile
         val line = quotes.reflect.Position.ofMacroExpansion.startLine + 1
         Expr(line)
       }
       inline implicit def line: Int = ${ lineImpl }
       
       def fileImpl(using Quotes): Expr[String] = {
         import quotes.reflect._
         Expr(quotes.reflect.Position.ofMacroExpansion.sourceFile.path)
       }
       
       inline implicit def file: String = ${ fileImpl }
                                                                                                                          
scala> import scalatags.Text.all._
                                                                                                                          
scala> h1("hello")
val res0: scalatags.Text.TypedTag[String] = <h1>hello</h1>
                                                                                                                          
scala> h1("hello").render
val res1: String = "<h1>hello</h1>"

@bishabosha
Copy link
Member

bishabosha commented Nov 11, 2025

@lihaoyi in the CI failure it looks like coursier isn't on the classpath

@lihaoyi
Copy link
Contributor Author

lihaoyi commented Nov 11, 2025

@Gedochao @hamzaremmal This should be ready to merge. CI is green, the red job is maven central flakiness

Actually maybe not yet, still fiddling with it

@lihaoyi lihaoyi changed the title Support //> using dep "..." directives in Scala REPL Support :dep ... to add library dependenceies in the Scala REPL, add helpful message to //> using dep "..." Nov 11, 2025
@lihaoyi
Copy link
Contributor Author

lihaoyi commented Nov 12, 2025

@Gedochao @hamzaremmal @bishabosha I decided to go with :dep rather than //> using dep.

  1. I think it fits much better into the REPL which already universally supports a :command syntax. In contrast, //> using is completely new to the REPL, and would be a bit out of place in REPLs when integrated into other tools like Mill or SBT which do not support the //> using syntax.
  2. :dep also lets us hook into :help, autocomplete, etc. for free whereas //> using would require us to re-implement all that surrounding infrastructure
  3. :dep is a lot shorter to type than //> using dep, which matters in the REPL

For now I left the //> using parsing logic in place to provide a nice error message telling people to use :dep, which should solve the problem of people entering //> using dep and wondering why it doesn't work.

This doesn't close off the possibility of supporting //> using later on, but I think for now :dep is the way to go

lihaoyi and others added 2 commits November 12, 2025 04:02
Co-authored-by: Jamie Thompson <bishbashboshjt@gmail.com>
Co-authored-by: Jamie Thompson <bishbashboshjt@gmail.com>
@Gedochao
Copy link
Contributor

@lihaoyi we already have a :jar command, which adds a local dependency to the REPL's classpath (check #22343)
I'd be more leaning towards extending that functionality (possibly with :dep as an alias), rather than introducing a completely new REPL command for something very similar/adjacent
That being said, while I think having //> using dep <dependency> syntax is very much desired (rule of least surprise - people expect that to work and have been surprised it doesn't work for a long time), I'm not sure we want a :dep.
Adding it to the next Scala Core meeting agenda.

@Gedochao Gedochao added the stat:needs decision Some aspects of this issue need a decision from the maintainance team. label Nov 12, 2025
@SethTisue
Copy link
Member

I don’t think :jar is much of a precedent since I think virtually nobody uses it or even knows about it; I cannot recall it ever being mentioned even a single time in forums or chat

@SethTisue
Copy link
Member

Another thought: if //> using dep ... works, will create a user expectation that other using directives might work as well, such as //> using option ....

Currently it seems the error just says "Unrecognized directive"; it would be nice if it also said at that point which directives are supported, so it isn't a guessing game.

@Gedochao
Copy link
Contributor

Another thought: if //> using dep ... works, will create a user expectation that other using directives might work as well, such as //> using option ....

Currently it seems the error just says "Unrecognized directive"; it would be nice if it also said at that point which directives are supported, so it isn't a guessing game.

Yup... we should perhaps do that once we do add support for the ones we want in the REPL (//> using dep, perhaps //> using repository).

@Gedochao
Copy link
Contributor

@lihaoyi We discussed it on today's Scala Core.

  • the :dep approach is fine.
  • it's okay to keep it separate from :jar.
  • we'd like //> using dep down the line, but perhaps we can do it one step at a time.
    Thanks for putting so much effort into the REPL, by the way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat:needs decision Some aspects of this issue need a decision from the maintainance team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants