How to decode Scala compiler generated names - scala

Our code is killing the Scala compiler with this message:
[error] how can getCommonSuperclass() do its job if different class symbols
get the same bytecode-level internal name: scala/Tuple2$mcJD$sp
To figure it out I'm trying to understand what Tuple2$mcJD$sp is supposed to be. Is it the class generated for (Long, Double)? Is this documented somewhere? Thanks!
Some clues I have found so far:
I think the type abbreviations match those documented in Class.getName.
The name is generated in SpecializeTypes.specializedName. According to the code, the format is m<abbreviated method specialization types>c<abbreviated class specialization types>$sp.
Maybe it's considered a compiler internal thing and not documented anywhere.

Related

can`t bind[SttpBackend[Try, Nothing]]

I want to use sttp library with guice(with scalaguice wrapper) in my app. But seems it is not so easy to correctly bind things like SttpBackend[Try, Nothing]
SttpBackend.scala
Try[_] and Try[AnyRef] show some other errors, but still have no idea how it should be done correctly
the error I got:
kinds of the type arguments (scala.util.Try) do not conform to the expected kinds of the type parameters (type T).
[error] scala.util.Try's type parameters do not match type T's expected parameters:
[error] class Try has one type parameter, but type T has none
[error] bind[SttpBackend[Try, Nothing]].toProvider[SttpBackendProvider]
[error] ` ^
SttpBackendProvider looks like:
def get: SttpBackend[Try, Nothing] = TryHttpURLConnectionBackend(opts)
complete example in scastie
interesting that version scalaguice 4.1.0 show this error, but latest 4.2.2 shows error inside it with converting Nothing to JavaType
I believe you hit two different bugs in the Scala-Guice one of which is not fixed yet (and probably even not submitted yet).
To describe those issues I need a fast intro into how Guice and Scala-Guice work. Essentially what Guice do is have a mapping from type onto the factory method for an object of that type. To support some advanced features types are mapped onto some internal "keys" representation and then for each "key" Guice builds a way to construct a corresponding object. Also it is important that generics in Java are implemented using type erasure. That's why when you write something like:
bind(classOf[SttpBackend[Try, Nothing]]).toProvider(classOf[SttpBackendProvider])
in raw-Guice, the "key" actually becomes something like "com.softwaremill.sttp.SttpBackend". Luckily Guice developers have thought about this issue with generics and introduced TypeLiteral[T] so you can convey the information about generics.
Scala type system is more reach than in Java and it has some better reflection support from the compiler. Scala-Guice exploits it to map Scala-types on those more detailed keys automatically. Unfortunately it doesn't always work perfectly.
The first issue is the result of the facts that the type SttpBackend is defined as
trait SttpBackend[R[_], -S]
so it uses it expects its first parameter to be a type constructor; and that originally Scala-Guice used the scala.reflect.Manifest infrastructure. AFAIU such higher-kind types are not representable as Manifest and this is what the error in your question really says.
Luckily Scala has added a new scala.reflect.runtime.universe.TypeTag infrastructure to tackle this issue in a better and more consistent way and the Scala-Guice migrated to its usage. That's why with the newer version of Scala-Guice the compiler error goes away. Unfortunately there is another bug in the Scala-Guice that makes the code fail in runtime and it is a lack of handling of the Nothing Scala type. You see, the Nothing type is a kind of fake one on the JVM. It is one of the things where the Scala type system is more reach than the Java one. There is no direct mapping for Nothing in the JVM world. Luckily there is no way to create any value of the type Nothing. Unfortunately you still can create a classOf[Nothing]. The Scala-to-JVM compiler handles it by using an artificial scala.runtime.Nothing$. It is not a part of the public API, it is implementation details of specifically Scala over JVM. Anyway this means that the Nothing type needs additional handling when converting into the Guice TypeLiteral and there is none. There is for Any the cousin of Nothing but not for Nothing (see the usage of the anyType in TypeConversions.scala).
So there are really two workarounds:
Use raw Java-based syntax for Guice instead of the nice Scala-Guice one:
bind(new TypeLiteral[SttpBackend[Try, Nothing]]() {})
.toInstance(sttpBackend) // or to whatever
See online demo based on your example.
Patch the TypeConversions.scala in the Scala-Guice as in:
private[scalaguice] object TypeConversions {
private val mirror = runtimeMirror(getClass.getClassLoader)
private val anyType = typeOf[Any]
private val nothingType = typeOf[Nothing] // added
...
def scalaTypeToJavaType(scalaType: ScalaType): JavaType = {
scalaType.dealias match {
case `anyType` => classOf[java.lang.Object]
case `nothingType` => classOf[scala.runtime.Nothing$] //added
...
I tried it locally and it seems to fix your example. I didn't do any extensive tests so it might have broken something else.

json4s JValue scala classTag works wrong

In my code, I use classTag[JValue] want to get org.json4s.JsonAST.JValue ,
but actually it returns org.json4s.JsonAST$JValue, it is strange ! why there is the $?
I am new guy use scala ,could someone answer me ? thanks a lot
The name you use to refer to a class/method/etc. in your code and the name it has in bytecode produced by the compiler doesn't have to be the same. Scala compiler needs to be more of this name-mangling than the Java compiler, but this specific case is same for both.
The reason is that inner classes don't really exist on JVM: they are normal classes which have an additional field containing the outer instance. The JVM name of the class looks like <outer_class>$<inner_class>.
In Scala and Java, $ in a name generally indicates it's mangled in some way (though it is a legal character for programmers to use as well).

How to resolve ambiguous method reference in scala

Here is the specific issue I am encountering. I am using SLF4J Logger (The type of the variable logger below)
//After adding to a map
logger debug ("Adding {} = {}", key, value)
Here is what mouse hover in eclipse (and the compiler) tell me.
ambiguous reference to overloaded definition, both method debug in trait Logger of type (x$1: String, x$2: Object*)Unit and method debug in trait Logger of type (x$1: String, x$2: Any, x$3: Any)Unit match argument types (String,String,String)
I understand why they are ambiguous. I am certainly not arguing with the compiler :). I want to simply know how seasoned programmers solve this issue.
Here are the alternatives I can use
Create and array , and ride the Object* definition
logger debug ("Adding {} = {}", Array(key, value):_*)
Cast to Any
logger debug ("Adding {} = {}", key.asInstanceOf[Any], value.asInstanceOf[Any])
Neither approach is particularly appealing. Does the community have a better approach or suggestions for me?
Many thanks!
I would use
logger.debug("Adding {} = {}", key, value: Any)
Alternatively following can be used:
logger.debug("Adding {} = {}", Array(key, value):_*)
Please pay attention to :_*. Should you omit these symbols and it will call Object* method providing only 1 argument, which will be an array.
First off a nod of credit to #Shadowlands, #ArneClaassen and #OlgeRudenko.
As mentioned in the comments, this does seem to be known issue. That stopped me from trying to "solve" it. The next thing to do was to find a good work around that did not break Scala idioms.
With these constraints in mind I chose to go with String Interpolation as suggested above. I also switched to scala-logging. Quoting from their GitHub/README,
Scala Logging is a convenient and performant logging library wrapping SLF4J. It's convenient, because you can simply call log methods without checking whether the respective log level is enabled:
logger.debug(s"Some $expensive message!")
It's performant, because thanks to Scala macros the check-enabled-idiom is applied, just like writing this more involved code:
if (logger.isDebugEnabled) logger.debug(s"Some $expensive message!")
Thanks all! As far as I am concerned, this is resolved. If the commentators can post their answers, I will be happy to acknowledge them.
As always, feels good to be standing on the shoulders of friendly giants!
PS: I just verified that there is no execution cost to String interpolation if you are using scala-logging. My verification method was crude but effective.
log.debug{
{
throw new IllegalAccessException("This should not have been called with debug off!")
}
s"Added Header ${name}:${headerValue}"
}
Sure enough, when I set my log to DEBUG, the exception is thrown, as expected , but vanishes when I set it to a level higher.
And yes, I have already removed the IllegalAccessException part :).

Where can I find scala documentation which list all available method in String class

I was going through the api documentation page of scala but could not find string class specific method, may be I am missing something. Sorry for the noob question.
scala.Predef defines two implicit conversions from String: one to WrappedString and another to StringOps.
You will find all the String related methods in these two classes.

Why does Array.fill take an implicit scala.reflect.ClassManifest?

So I'm playing with writing a battlecode player in Scala. In battlecode certain classes are disallowed and there is a runtime exception if you ever try to access them. When I use the Array.fill function I get a message from the battlecode server saying [java] Illegal class: scala/reflect/Manifest$. This is the offending line:
val g_score = Array.fill[Int](rc.getMapWidth(), rc.getMapHeight())(0)
The method takes an implicit ClassManifest argument which has the following documentation:
A ClassManifest[T] is an opaque descriptor for type T. It is used by the compiler
to preserve information necessary for instantiating Arrays in those cases where
the element type is unknown at compile time.
But I do know the type of the array elements at compile time, as shown above I explicitly state that they will be Int. Is there a way to avoid this? To workaround I've written my own version of Array.fill. This seems like a hack. As an aside, does Scala have real 2D arrays? Array.fill seems to return an Array[Array[T]] which is the only way I found to write my own. This also seems inelegant.
Edit: Using Scala 2.9.1
For background information, see this related question: What is a Manifest in Scala and when do you need it?. In this answer, you will find an explanation why manifests are needed for arrays.
In short: Although the JVM uses type erasure, arrays are an exception and need a manifest. Since you could compile your code, that manifest was found (manifests are always available for proper types). Your error occurs at runtime.
I don't know the details of the battlecode server, but there are two possibilities: Either you are running your compiled classes with a binary incompatible version of Scala (difference in major version, e.g. compiled with Scala 2.9 and server uses 2.10). Or the server doesn't even have the scala-library.jar on its class path.
As said in the comment, manifests are deprecated in Scala 2.10 and replaced by ClassTag.
EDIT: So it seems the class loader is artificially restricting the allowed classes. My suggestion would be: Add a helper Java class. You can easily mix Java and Scala code. If it's just about the Int-Array instantiation, you could provide something like:
public static class Helper {
public static int[][] makeArray(int d1, int d2) { return new int[d1][d2](); }
}
(hope that's valid java code, a bit rusty)
Also, have you tried to create the outer array with new Array[Array[Int]](d1), and then iterate to create the inner arrays?