Reputation: 6537
Is it possible to create (enter) nested environments in Scala REPL, such that after exiting the nested environment, all variable bindings created within the exited environment will be lost?
Here is what I wish a session could look like:
scala> val x = 1
x: Int = 1
scala> enter // How to implement this?
// Entering nested context (type exit to exit)
scala> val x = 2
x: Int = 2
scala> val y = 3
y: Int = 3
scala> exit // How to implement this?
// Exiting nested context
scala> assert(x == 1)
scala> y
<console>:12: error: not found: value y
y
^
scala>
Upvotes: 2
Views: 117
Reputation: 55569
This isn't possible with the current Scala REPL, but you can achieve something similar using the Ammonite REPL:
Welcome to the Ammonite Repl 0.8.2
(Scala 2.12.1 Java 1.8.0_121)
@ val x = 1
x: Int = 1
@ repl.sess.save("first")
res1_1: ammonite.repl.SessionChanged =
@ val x = 2
x: Int = 2
@ val y = 3
y: Int = 3
@ repl.sess.save("second") ; repl.sess.load("first")
res4_1: ammonite.repl.SessionChanged =
Removed Imports: Set('y, 'res1_1, 'res1_0)
@ y
cmd5.sc:1: not found: value y
val res5 = y
^
Compilation Failed
@ x
res5: Int = 1
These sessions aren't nested exactly the way you describe, but are easy to track by name, and can overlap. That is after repl.sess.save("first")
, you still have access to the original x
if you don't override it.
After playing around with it some more, I was able to concoct a simple object that uses a stack to track the sessions and load/save them. It can be placed in ~/.ammonite/predef.sc
to load automatically with the Ammonite REPL:
object SessionStack {
case class AmmSession(id: Int = 1) {
def name = s"session_${id}"
def next = AmmSession(id + 1)
}
private var sessions = collection.mutable.Stack.empty[AmmSession]
private var current = AmmSession()
def enter: Unit = {
sessions.push(current.copy())
repl.sess.save(current.name)
current = current.next
}
def exit: Unit = if(sessions.nonEmpty) {
current = sessions.pop()
repl.sess.load(current.name)
} else {
println("Nothing to exit.")
}
}
import SessionStack._
I haven't tested this rigorously, so there may be an edge-case that isn't covered, but I was able to go a few levels deep easily and then peel back the layers.
Upvotes: 1