Can Scala REPL on SBT call people's own scripts? (Like OptiML?) - scala

I know sbt console will open an interactive Scala REPL and load in all the library dependencies so people can test Scala code right there. However, I wonder if there's anyway to use and treat in a way so that people can interact with my programs directly, instead of interacting with libraries.
For example, if I write a Vector class, how can someone call it from sbt console or any other Scala REPL interface??
Think of it as that you are trying to write a Scala library but you want to provide a simple REPL interface for people to interact with it, like R, instead of asking people to add the library as dependency.
The effect is similar as described here: http://stanford-ppl.github.io/Delite/optiml/getting_started.html

Maybe this will help.
You can use initialCommands key in sbt to do this
So in build.sbt if you put
initialCommands in console := """import my.project._
val myObj = MyObject("Hello", "World")
"""
after you type 'console', you can start using myObj or the classes in my.project
http://www.scala-sbt.org/0.13.5/docs/Howto/scala.html#initial

Yes you can, but you cannot use modified code without reloading the REPL. Just run:
sbt "~ ; console"
And then import your classes with import your.package._ and use them from there.
If you make any changes to your library code, just hit CTRL+D or :quit and it will detect file changes, compile them and enter the REPL again. You can then use the history (navigating with the arrows up/down) to execute anything from the previous session again.

Related

How can I change the compiler flags of an sbt project without causing recompilation?

It often comes up during testing and debugging a Scala project built with sbt that I need to pass some extra compiler flags for a particular file. For example -Xlog-implicits to debug implicit resolution problems. However, changing scalacOptions either in build.sbt or the console invalidates the cache and causes the whole project / test suite to be recompiled. In addition to being annoying to wait so long, this also means that a lot of noise from irrelevant files is printed. Instead it would be better if I could compile a specific file with some extra flags from the sbt console, but I did not find a way to do this.
Problem
The reason why changing the scalac options triggers recompilation is because Zinc, Scala's incremental compiler, cannot possibly now which compiler flags affect the semantics of the incremental compilation, so it's pessimistic about it. I believe this can be improved, and some whitelisted flags can be supported, so that next time people like you don't have to ask about it.
Nevertheless, there's a solution to this problem and it's more generic than it looks like at first sight.
Solution
You can create a subproject in your sbt build which is a copy of the project you want to "log implicits" in, but with -Xlog-implicits enabled by default.
// Let's say foo is your project definition
lazy val foo = project.settings(???)
// You define the copy of your project like this
lazy val foo-implicits = foo
.copy(id = "foo-implicits")
.settings(
target := baseDirectory.value./("another-target"),
scalacOptions += "-Xlog-implicits"
)
Note the following properties of this code snippet:
We redefine the project ID because when we reuse a project definition the ID is still the same as the previous one (foo in this case). Sbt fails when there are projects that share the same id.
We redefine the target directory because we want to avoid recompilation. If we keep the same as before, then recompiling foo-implicits will delete the compilation products of the previous compilation (and viceversa). That's exactly what we want to avoid.
We add -Xlog-implicits to the Scalac options as you request in this question. In a generic solution, this piece of code should go away.
When is this useful?
This is useful not only for your use case, but when you want to have different modules of the same project in different Scala versions. The following has two benefits:
You don't use cross-compilation in sbt ++, which is known to have some memory issues.
You can add new library dependencies that only exist for a concrete Scala version.
It has more applications, but I hope this addresses your question.

Evaluating Scala with twitter Eval and Scala notebook

I've been using twitter Eval function to compile Scala functions. But would prefer to evaluate the function as being provided at project scala-notebook (https://github.com/Bridgewater/scala-notebook)
Is scala-notebook hooking up to the internal repl of machine its running on ?
How is it different to twitter Eval library (https://twitter.github.io/util/docs/index.html#com.twitter.util.Eval) ?
Both scala-notebook and twitter-eval use the scala-compiler tool under the hood to compile and interpret the text as scala code. So, technically there is no difference between those two with regard to how they compile the source code.
Just to shed some light on how they both do that, check out the below files:
scala-notebook: https://github.com/Bridgewater/scala-notebook/blob/master/kernel/src/main/scala/com/bwater/notebook/kernel/Repl.scala
twitter-eval: https://github.com/twitter/util/blob/develop/util-eval/src/main/scala/com/twitter/util/Eval.scala
As you can see, both of the use the scala-compiler. The compiler classes and utilities are located in the package 'scala.tools'

Build a scala interpreter in the browser

My first contact with Scala was through the SimplyScala tutorial: You don't need to install anything and can just start to code. After some hours I fell in love with the language...
Years later, I have written a web documentation for a Scala library as a Play Application. It would be cool to build something like SimplyScala and integrate it in the documentation, so that the user can enter Scala commands in the browser and get the result back.
SimplyScala works like LotREPLS (old Open-Source-Java-Project with just few LOCs) on the Google App Engine.
Is is also possible to create something like this on my own server without getting security holes (f.ex. the user should not read files from the server...)?
I just need the "base" of the Scala language without any imports just like in SimplyScala.
My first idea is to write an own SecurityManager and handle time-outs so that the user cannot consume too much server time. Is there any easier way or an existing open-source project?
Or is it just more rational to advice the user to install Scala and work with the terminal instead of the browser? ;-)
On the Scala homepage is a similar Play-project idea for the Summer of Code 2012 Scala Projects: but I cannot find any results.
Probably the most secure so far is http://www.scala-js-fiddle.com/ (code on GitHub) simply because it does not even run the code on the server, but on the client!
The gotcha is: it's not truly Scala code, it is Scala.js, which is a dialect of Scala, is still experimental, etc. But it might be enough for your use case.
Answering my own question:
Scala Consoles, that don't care about security (?):
Scala Web Console
Scala IDE
Tryscala
One web interface which handles somehow security:
The impressive Scalakata project, Source is on GitHub.
It's a Lift project that defines an own security manager (see src/main/scala/com.github.masseguillaume/security) and handle time-outs (see src/main/scala/com.github.masseguillaume/service/KateEval.scala). Now I have to think, if that is secure enough...
https://codebrew.io/ seems to work quite well as Scala REPL
code available at https://github.com/CodeBrew-io
with: libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value
Compiler (scala.tools.nsc.Global)
This is the most accurate method to evaluate scala code.
compileSources will add a new class in the classloader
usage
Repl
IMain
usage
JSR-223
import javax.script.ScriptEngineManager
val e = new ScriptEngineManager().getEngineByName("scala")
e.put("n", 10)
e.eval("1 + n") // 11
Reflection Toolbox
import scala.reflect.runtime.{currentMirror => cm}
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val tb = cm.mkToolBox()
tb.eval(tb.parse("1+1"))
// res0: Any = 2
Presentation (interactive) compiler (scala.tools.nsc.interactive.Global)
This is for autocompletion and other interactive features.
doc
usage

Issue with BufferedReader.readLine using sbt run or sbt console

My question is quick I'm working on a small console for reading input in and then calling the appropriate code. I'm using sbt and I've encountered an issue where when I try to read input after running my program with sbt run, inside sbt console, or even in the plain old scala interpreter.
The prompt appears to just hang, but if I hit return it does actually read the input in. Though the shell's buffer remains empty. Here is the general code I've been trying that has been giving me the issue.
import java.io._
val s = new BufferedReader(new InputStreamReader(System.in))
val line = s.readLine
println(line)
Does anyone know why this is, and if so is there a way to fix this? I would love to be able to see what I type when I run my program from sbt. Without seeing my typing in the shell it makes the testing and development of my project much less enjoyable.
This is really a Java API question, although in Scala. BufferedReader.readLine() will consume all the characters you type from System.in until it has a whole line, at which time it will return the line as you said.
Console input was difficult in Java with the original java.io classes. Prior to Java6, I've seen a couple of messy solutions to this, but fortunately a new class was introduced with that release to make it much easier: java.io.Console. I think it then becomes as simple as
val line = System.console.readLine
println(line)

Why am I not seeing my macro-created functions in the new slime session? (clojure)

In my clojure code, I have a few functions which are created with calls to custom macros. Typically, the macros would take a data structure of some sort and create a method from it.
This is a contrived example:
(create-function {:name "view-data" ...})
which would create a new function called view-data. (My database queries are data-driven, so I can create a function with an indicative name that calls a specific query)
My problem is that when I run the mvn clojure:swank target and connect to the slime session from emacs these functions aren't visible. I have to visit the file and compile it myself with C-c C-k for the functions to be created.
The maven output suggests that the files themselves compile fine, but the slime session doesn't know about the functions.
Any ideas why this might be happening?
I have a file in my project that requires all the namespaces which makes all the functions from every where available in the repl. perhaps there is a more slime-elegant way of doing this, but this hack has been very reliable for me.
Note that in clojure, compiling and loading are separate steps. You can generate all the class files you like, but if they're not loaded, it won't affect the running process.
I don't know enough about clojure:swank for maven, but it sounds to me that, like leiningen, the swank target will only set up the classpath for your project and load the swank code but not any of the code in your project. So you will still have load load your code in some way after that (for instance; from Emacs/SLIME, using some other target/plugin or from the REPL).