In the latest reflection API in scala-2.12, I realise that the standard code to detect a (probably erased) type works strangely in some cases.
Namely, detection works for anonymous class:
{
val ll = new AnyRef with Function1[String, Int] with Serializable {
override def apply(v: String) = v.toInt
}
val clazz = ll.getClass
val mirror = runtimeMirror(clazz.getClassLoader)
val sym = mirror.classSymbol(clazz)
print(sym.selfType)
}
(I know this output looks super weird but at least it is an erased type)
⦠but doesnāt work for anonymous function / lambda:
val ll = { v: String =>
v.toInt
}
val clazz = ll.getClass
val mirror = runtimeMirror(clazz.getClassLoader)
val sym = mirror.classSymbol(clazz)
print(sym.selfType)
assertion failed: no symbol could be loaded from class org.apache.spark.ml.dsl.utils.refl.ScalaTypeSpike$$Lambda$356/2114537280 in package refl with name ScalaTypeSpike$$Lambda$356/2114537280 and classloader sun.misc.Launcher$AppClassLoader@18b4aac2
java.lang.AssertionError: assertion failed: no symbol could be loaded from class .refl.ScalaTypeSpike$$Lambda$356/2114537280 in package refl with name ScalaTypeSpike$$Lambda$356/2114537280 and classloader sun.misc.Launcher$AppClassLoader@18b4aac2
at scala.reflect.internal.SymbolTable.throwAssertionError(SymbolTable.scala:184)
at scala.reflect.runtime.JavaMirrors$JavaMirror.classToScala1(JavaMirrors.scala:1061)
at scala.reflect.runtime.JavaMirrors$JavaMirror.$anonfun$classToScala$1(JavaMirrors.scala:1019)
at scala.reflect.runtime.JavaMirrors$JavaMirror.$anonfun$toScala$1(JavaMirrors.scala:130)
at scala.reflect.runtime.TwoWayCaches$TwoWayCache.$anonfun$toScala$1(TwoWayCaches.scala:50)
at scala.reflect.runtime.TwoWayCaches$TwoWayCache.toScala(TwoWayCaches.scala:46)
at scala.reflect.runtime.JavaMirrors$JavaMirror.toScala(JavaMirrors.scala:128)
at scala.reflect.runtime.JavaMirrors$JavaMirror.classToScala(JavaMirrors.scala:1019)
at scala.reflect.runtime.JavaMirrors$JavaMirror.classSymbol(JavaMirrors.scala:231)
at scala.reflect.runtime.JavaMirrors$JavaMirror.classSymbol(JavaMirrors.scala:68)
Is it going to be a deliberate design for Scala 2.12+ and Dotty?
Because of the issues with getClass.getSimpleName, this is my preferred workaround for getting a reasonable name for somethingās class or type, so Iād really like this to return something reasonable.
Note: yes the issue for this is closed, but itās closed as ānot our problem, upgrade to JDK9ā, which isnāt really feasible (at least based on the posted guidelines, the most recent fully-supported JDK is 8)
It is NOT relevant to #2034, the error being thrown here is AssertionError, not ClassNotFoundException.
For #2034 though: why abandoning a JDK that is in active support by oracle, and is the latest version that is being actively supported by the scala team?
To clarify: itās related because it demonstrates that none of the available methods are universal - there isnāt a single way to get a printable representation of the type that will work in all circumstances.
getSimpleName dies if itās doubly nested, and selfType fails for lambdas.
Moreover, #2034 is really a Java bug, as linked on the ticket: Loading.... We donāt follow the Java language spec, because weāre not Java; we do follow the JVM spec here, but the implementation of getSimpleName doesnāt. Note that the original JDK bug report mentions groovy, not scala: this isnāt because Scala itself is doing anything wrong.
Paul fixed it a while ago, but his patch is probably lost to time, and now that it is fixed in the JDK I think itās perfectly reasonable to say āuse a non-buggy version of the software with the bugā.
This would be true, if any of the non-buggy versions of the JDK were fully supported by Scala. As it is, the point isnāt that Scala is doing anything wrong per se, itās that the alternative to selfType is also currently broken in some cases.
As they didnāt backport the fix to JDK 8, fixing selfType is pretty much the only way forward we have any control over.
Well, itās not even selfType here but classSymbol, and the problem is simply that the class org.apache.spark.ml.dsl.utils.refl.ScalaTypeSpike$$Lambda$356/2114537280 doesnāt exist until the JVM makes it at runtime; its name isnāt even stable! So from Scalaās perspective itās not easy to talk about that class as a āclassā. Seth did a better job of explaining this on the ticket.
Also, youāre mixing up the two problems here: @tribbloidās complaint isnāt fixed in Java 9.
We could also get to a point when we can say Java 9 is fully supported. I believe the only missing bit is compatibility with JPMS, which has a prototype implementation already.
@hrhino is right: we were mostly talking about an error case where a different exception (MatchError which generally indicates an incomplete pattern matching warning at compile time) is thrown at a different time.
Iām wondering why the runtime class needs to be stable? Both java & scala supports dynamic classloading, metaprogramming capability is not supported directly but is mentioned in several libraries.
So from Scalaās perspective itās not easy to talk about that class as a āclassā
Yes but functions should have classes, otherwise how would you define āhigh-level functionā?
Eh? Re: 11828, I donāt think there is any agreement here that there is even any actual problem, let alone a plan or roadmap for a āsolutionā. (The getSimpleName stuff, 2034, is something else.)
Iāve had a good poke at the OpenJDK internals, and Iām pretty sure thereās no way to go from a lambda class to its implementing method. So, even if we wanted to allow classSymbol(((x: Int) => x).getClass), I donāt think thereās a way we can do that without moving away from Java 8ās LambdaMetaFactory.
@tribbloid: can you describe your actual goal here? Itās possible that your use case can be supported somehow else (but I make no promises).
The lambda type can be easily inferred in compile-time (using implicit), since it is not a generic type, it should not be affected by type erasure, and inferring it in runtime should be equally easy or only slight difficult using reflection.
āto go from a lambda class to its implementing methodā: I havenāt tried it yet but I was under the impression that Java reflection can do that without much surprised, let me post the result later ā¦
What you say is quite clear isnāt quite specific. Specifically, it uses terms in a context that arenāt defined cleanly.
Do you have a concrete proposal at this time, or are you still gathering input for shaping your proposal? If itās the latter, some practical use cases would be good.