This question already has answers here:
How do I get the Scala version from within Scala itself?
(4 answers)
Closed 1 year ago.
When trying to run some code in online interpreters or with IRC bots, I always wonder which version of Scala they support.
Is there a way to retrieve the version of Scala from within the interpreter?
For Scala 2, use scala.util.Properties.versionNumberString (or versionString):
scala> scala.util.Properties.versionString
val res0: String = version 2.13.6
scala> scala.util.Properties.versionNumberString
val res1: String = 2.13.6
For Scala 3, if you do the same thing, you may be surprised by the answer:
% scala3 -version
Scala code runner version 3.0.1 -- Copyright 2002-2021, LAMP/EPFL
% scala3
scala> scala.util.Properties.versionNumberString
val res0: String = 2.13.6
That's because Scala 3.0.x uses the Scala 2 standard library as-is, to aid migration, and makes only a small number of additions. (Eventually the standard libraries will no longer remain synchronized like this.)
Here's how to get the Scala 3 compiler version:
scala> dotty.tools.dotc.config.Properties.simpleVersionString
val res0: String = 3.0.1
This only works if the scala3-compiler JAR is on your classpath. (In the standard Scala 3 REPL, it is; in some other environments, it might not be.)
If the compiler isn't on your classpath and you want the full Scala 3 version string, see Dmitrii's answer.
If the compiler isn't on your classpath but you just want to find out at runtime whether you're on Scala 2 or 3, well... perhaps there's a cleaner/better way, you tell me, but one way that works is:
util.Try(Class.forName("scala.CanEqual")).isSuccess
Here, the choice of scala.CanEqual is arbitrary, it could be any of the small number of classes that are in scala3-library but not scala-library.
But if you are tempted to go that route, you might instead consider including version-specific source in your project, or passing the Scala version via sbt-buildinfo.
scala> scala.util.Properties.versionMsg
res: String = Scala library version 2.9.0.1 -- Copyright 2002-2011, LAMP/EPFL
Looks of course like the library version and not like the language version, but I think currently there won’t be a real difference in practice.
If you need just the version number without the "version" keyword you can use versionNumberString function.
scala> scala.util.Properties.versionNumberString
res1: String = 2.12.3
If you want to get the exact Scala 3 version, you can read it from the Manifest file
.../scala3-library_3-3.0.1.jar!/META-INF/MANIFEST.MF
import java.io.FileInputStream
import java.util.jar.JarInputStream
val scala3LibJar = classOf[CanEqual[_, _]].getProtectionDomain.getCodeSource.getLocation.toURI.getPath
val manifest = new JarInputStream(new FileInputStream(scala3LibJar)).getManifest
manifest.getMainAttributes.getValue("Implementation-Version")
Example in Scastie:
Related
I recently revived an old library that was written in scala 2.9, and I created a new scala project using scala 2.13.2
I am getting errors like the following:
type mismatch;
found : scala.collection.mutable.Buffer[Any]
[error] required: Seq[Any]
Was there a specific change between 2.9 to 2.13.2 that involved not implicitly casting sequences or something that might solve many of these types of compile errors?
I had to add .toSeq to many of my function return statements that were vals of Buffer[Any] that needed to be passed as an arguement to a function expected a Sequence.
Quite a lot things happened in the last 7+ years (including rewrite of the collections library).
If adding .toSeq solves your problem - just go for it.
If you want to know what exactly has changed - try upgrading version-by version: first upgrade to scala-2.10., then to 2.11., then 2.12.*, then, finally, to 2.13.2.
At each upgrade you'll probably see deprecation warnings. Fix them before upgrading to the next version.
Brave, but perhaps bad form, to disturb the dead. Nevertheless, maybe pass mutable.Buffer as mutable.Seq instead of Seq which is by default immutable.Seq. Consider
val mb = mutable.Buffer(11, Some(42))
val ms: mutable.Seq[Any] = mb // OK
val is: Seq[Any] = mb // NOK
I have an interface:
trait MyInterface {
def doSomething(usefulName : Int) : Unit
}
I have a macro that iterates over the methods of the interface and does stuff with the method names and parameters. I access the method names by doing something like this:
val tpe = typeOf[MyInterface]
// Get lists of parameter names for each method
val listOfParamLists = tpe.decls
.filter(_.isMethod)
.map(_.asMethod.paramLists.head.map(sym => sym.asTerm.name))
If I print out the names for doSomething's parameters, usefulName has become x$1. Why is this happening and is there a way to preserve the original parameter names?
I am using scala version 2.11.8, macros paradise version 2.1.0, and the blackbox context.
The interface is actually java source in a separate sbt project that I control. I have tried compiling with:
javacOptions in (Compile, compile) ++= Seq("-target", "1.8", "-source", "1.8", "-parameters")
The parameters flag is supposed to preserve the names, but I still get the same result as before.
This has nothing to do with macros and everything to do with Scala's runtime reflection system. In a nutshell, Java 8 and Scala 2.11 both wanted to be able to look up parameter names and each implemented their reflection system to do it.
This works just fine if everything is Scala and you compile it together (duh!). Problems arise when you have a Java class that has to be compiled separately.
Observations and Problem
First thing to notice is that the -parameters flag is only since Java 8, which is about as old as Scala 2.11. So Scala 2.11 is probably not using this feature to lookup method names... Consider the following
MyInterface.java compiled with javac -parameters MyInterface.java
public interface MyInterface {
public int doSomething(int bar);
}
MyTrait.scala compiled with scalac MyTrait.scala
class MyTrait {
def doSomething(bar: Int): Int
}
Then, we can use MethodParameterSpy to inspect the parameter information name that the Java 8 -parameter flag is supposed to give us. Running it on the Java compiled interface, we get (and here I abbreviated some of the output)
public abstract int MyInterface.doSomething(int)
Parameter name: bar
but in the Scala compiled class, we only get
public abstract int MyTrait.doSomething(int)
Parameter name: arg0
Yet, Scala has no problem looking up its own parameter names. That tells us that Scala is actually not relying on this Java 8 feature at all - it constructs its own runtime system for keeping track of parameter names. Then, it comes as no surprise that this doesn't work for classes from Java sources. It generates the names x$1, x$2, ... as placeholders, the same way that Java 8 reflection generates the names arg0, arg1, ... as placeholders when we inspected a compiled Scala trait. (And if we had not passed -parameters, it would have generated those names even for MyInterface.java.)
Solution
The best solution (that works in 2.11) I can come up with to get the parameter names of a Java class is to use Java reflection from Scala. Something like
$ javac -parameters MyInterface.java
$ jar -cf MyInterface.jar MyInterface.class
$ scala -cp MyInterface.jar
scala> :pa
// Entering paste mode (ctrl-D to finish)
import java.lang.reflect._
Class.forName("MyInterface")
.getDeclaredMethods
.map(_.getParameters.map(_.getName))
// Exiting paste mode, now interpreting.
res: Array[Array[String]] = Array(Array(bar))
Of course, this will only work if you have the -parameter flag (else you get arg0).
I should probably also mention that if you don't know if your method was compiled from Java or from Scala, you can always call .isJava (For example: typeOf[MyInterface].decls.filter(_.isMethod).head.isJava) and then branch on that to either your initial solution or what I propose above.
Future
Mercifully, this is all a thing of the past in Scala 2.12. If I am correctly reading this ticket, that means that in 2.12 your code will work for Java classes compiled with -parameter and, my Java reflection hack will also work for Scala classes.
All's well that ends well?
I'm trying in Scala to get a list from a config file like something.conf with TypeSafe.
In something.conf I set the parameter:
mylist=["AA","BB"]
and in my Scala code I do:
val myList = modifyConfig.getStringList("mylist")
Simple configuration parameters works fine but could somebody give me an example of how to extract a list?
As #ghik notes, the Typesafe Config library is Java based, so you get a java.util.List[String] instead of a scala.List[String]. So either you make a conversion to a scala.List:
import collection.JavaConversions._
val myList = modifyConfig.getStringList("mylist").toList
Or (probably less awkward) you look for a Scala library. The tools wiki links at least to these maintained libraries:
Configrity
Bee Config
(Disclaimer: I don't use these, so you will have to check that they support your types and format)
For the record, since Scala 2.12 JavaConversions are deprecated so you can:
import collection.JavaConverters._
val myList: List[String] = modifyConfig.getStringList("mylist").asScala.toList
You can try my scala wrapper https://github.com/andr83/scalaconfig - it supports reading native scala types directly from config object. In your case it will look:
val myList = modifyConfig.as[List[String]]("mylist")
Starting Scala 2.13, the standard library provides Java to Scala implicit list conversions via scala.jdk.CollectionConverters:
import scala.jdk.CollectionConverters._
val myList: List[String] = conf.getStringList("mylist").asScala.toList
This replaces deprecated packages scala.collection.JavaConverters/JavaConversions.
I can't use scalax because it is in a state between sbt 0.7.7 and sbt 0.11.2 and will not install on windows. (it is missing org.scala-tools.sbt#sbt_2.7.7;0.4.7-p10 even though I have downloaded that and changes scripts to match - newbie well out of his depth).
I can find no examples in the web without scalax.
All I want to do is write some lines of text to a file. However I don't want to have all lines in memory at once.
Can someone point me at an example?
Scala 2.9, Windows 7 - 64 bit.
The easiest thing to do would probably be using java.io.PrintWriter like so:
scala> val pw = new java.io.PrintWriter("/tmp/foo.txt")
pw: java.io.PrintWriter = java.io.PrintWriter#1e1ff563
scala> pw.println("Hello")
scala> pw.close()
You might want to look up PrintWriter here.
I have a Set in Scala (I can choose any implementation as I am creating the Set. The Java library I am using is expecting a java.util.Set[String].
Is the following the correct way to do this in Scala (using scala.collection.jcl.HashSet#underlying):
import com.javalibrary.Animals
var classes = new scala.collection.jcl.HashSet[String]
classes += "Amphibian"
classes += "Reptile"
Animals.find(classes.underlying)
It seems to be working, but since I am very new to Scala I want to know if this is the preferred way (any other way I try I am getting a type-mismatch error):
error: type mismatch;
found : scala.collection.jcl.HashSet[String]
required: java.util.Set[_]
If you were asking about Scala 2.8, Java collections interoperability is supplied by scala.collection.JavaConversions. In this case, you want JavaConversions.asSet(...) (there's one for each direction, Java -> Scala and Scala -> Java).
For Scala 2.7, each scala.collection.jcl class that wraps a Java collection has an underlying property which provides the wrapped Java collection instance.
Since Scala 2.12.0 scala.collection.JavaConversions is deprecated:
Therefore, this API has been deprecated and JavaConverters should be used instead. JavaConverters provides the same conversions, but through extension methods.
And since Scala 2.8.1 you can use scala.collection.JavaConverters for this purpose:
import scala.collection.JavaConverters._
val javaSet = new java.util.HashSet[String]()
val scalaSet = javaSet.asScala
val javaSetAgain = scalaSet.asJava
For 2.7.x I highly recommend using: http://github.com/jorgeortiz85/scala-javautils
Note that starting Scala 2.13, package scala.jdk.CollectionConverters replaces deprecated packages scala.collection.JavaConverters/JavaConversions._:
import scala.jdk.CollectionConverters._
// val scalaSet: Set[String] = Set("a", "b")
val javaSet = scalaSet.asJava
// javaSet: java.util.Set[String] = [a, b]
javaSet.asScala
// scala.collection.mutable.Set[String] = Set(a, b)
In Scala 2.12 it is possible to use : scala.collection.JavaConverters.setAsJavaSet(scalaSetInstance)