I can haz no package-private class in Scala? - scala

Sorry for the catchy title. ;-)
I want to create a package-private class with a package-private method in Scala, so my class looks somewhat like this:
package net.java.truevfs.ext.pace
import ...
private[pace] abstract class AspectController(controller: FsController)
extends FsDecoratingController(controller) {
private[pace] def apply[V](operation: => V): V
... // lots of other stuff
}
However, if I use javap to check what the Scala compiler effectively creates, I get something like this:
$ javap -classpath target/classes net.java.truevfs.ext.pace.AspectController
Compiled from "AspectController.scala"
public abstract class net.java.truevfs.ext.pace.AspectController extends net.java.truevfs.kernel.spec.FsDecoratingController implements scala.ScalaObject{
public abstract java.lang.Object apply(scala.Function0);
...
}
This means that although the Scala compiler might respect the access restrictions, I could still call this class from any Java code, which is a clear encapsulation violation.
Am I missing something?
Is there a way to make this work as intended?

In addition to #RĂ©gis' answer, the reason Scala compiler doesn't make the class package-private is because by Scala rules it can be accessed from other packages: namely, subpackages of net.java.truevfs.ext.pace. E.g.
package net.java.truevfs.ext.pace.subpackage
import net.java.truevfs.ext.pace.AspectController
class Subclass extends AspectController { ... }
is legal in Scala, but in Java classes from net.java.truevfs.ext.pace.subpackage can't access package-private classes from net.java.truevfs.ext.pace.

You are not missing anything.
Many of the access restricitons in scala have no equivalent in java nor at the jvm level. The additional information is obviously right there in the .class file, but is there as custom annotations that only the scala compiler will interpret.
The scala object model can only partly be matched to the jvm object model, and a java compiler will only see this partial model.
I'd say that the match is pretty close and the scala compiler does a very good job at java interoperability, but nothings's perfect.

Not really a 100% correct answer...
You can make a package object if I want to do some fancy stuff in there with a private class. The package object is accessed like any other package.
The class MyClass is package private to that package object.
It's not package private however.
package object com.jasongoodwin.foo {
private class MyClass
class AnotherClass {
val myClass = new MyClass
}
}

Related

AbstractMethodError on obscure method name when upgrading from Scala 2.12 to 2.13

I am getting the following error:
java.lang.AbstractMethodError: Receiver class com.pack.ReceiverDAO does not define or inherit an implementation of the resolved method 'abstract void com$pack$proj$dao$JSDAO$_setter_$jsDAOApi_$eq(slick.jdbc.JdbcProfile$API)' of interface com.pack.proj.dao.JSDAO.
when I try to promote my code to Scala 2.13 from 2.12 (the dependency that's giving me issues, com.pack.proj, is compiled by Scala 2.12). I thought an easy way to get rid of this error is to implement a stub for it. However, at the moment, I don't have the source code for com.pack.proj.dao.JSDAO (which is what I extends in my "receiver", com.pack.ReceiverDAO) so I am not sure how to override com$pack$proj$dao$JSDAO$_setter_$jsDAOApi_$eq(slick.jdbc.JdbcProfile$API) w/o compilation errors like "overrides nothing". How can I override this inherited abstract method or otherwise get rid of this runtime error?
For the sake of completeness, I'd like to add that I needed to exclude some of the Scala_2.12-compiled Slick libraries when I declared the troublesome library, com.pack.proj as a dependency:
("com.pack.proj" % "js-dao_2.12" % ProjVer)
.exclude("com.typesafe.slick", "slick-hikaricp_2.12")
.exclude("com.github.tminglei", "slick-pg_2.12")
.exclude("com.typesafe.slick", "slick_2.12")
You simply cannot use a library that is compiled with 2.12 in a 2.13 project. It will inevitably break.
There is no real remedy other than use a version of that library that is compiled with 2.13, or not use it at all.
Make sure you're initialising your database in the same format as recommended. I.e. use a trait to define which extensions you wish to use and then extend this trait on a companion object.
import com.github.tminglei.slickpg._
trait MyPostgresProfile extends ExPostgresProfile
with PgArraySupport {
override val api = MyAPI
object MyAPI extends API with ArrayImplicits {
}
object MyPostgresProfile extends MyPostgresProfile
You can see a more complete example in the slick-pg README

Why does class name of a type in a package object contain "package" in runtime class name?

I'm trying to generate the runtime class name of a class that is defined in a package object.
Example:
package com.foo
package object bar {
case class MyCaseClass()
}
import bar._
MyCaseClass().getClass.getCanonicalName
The above will generate com.foo.bar.package.MyCaseClass
If I use WeakTypeTag it will correctly generate the type as com.foo.bar.MyCaseClass.
package com.foo
trait MyTrait
case class MyImpl extends MyTrait
def getType[T](t: T)(implicit weakTypeTag WeakTypeTag[T]): String = {
weakTypeTag.tpe.fullName
}
What is the reason for the above difference in behavior? I know I must be missing something about the Scala type system...
This isn't so much about the type system as about the encoding of package objects on the JVM. The JVM doesn't have package-level methods, for example, so the Scala compiler has to create a synthetic class that has static methods, inner classes, etc. corresponding to the definitions in the package object. That class is named package, an arbitrary but self-explanatory name that has the advantage of being a keyword in both Scala and Java, so it's unlikely to result in collisions with non-synthetic code.
Java's reflection APIs know nothing about Scala, so naturally they can't hide this encoding from you. When you call getClass.getCanonicalName you're seeing the actual class name, corresponding to the class file you'd find at com/foo/bar/package\$MyCaseClass.class when you compile your code.
Scala's reflection APIs do know about Scala's encoding of package objects, and they will hide the synthetic package class from you. This arguably makes sense, since the details of the encoding aren't in the spec (if I remember correctly?) and so may vary across platforms or language versions, etc.
The discrepancy is a little confusing, but this isn't the only time you'll run into differences—the Scala reflection API hides lots of mangling, etc. that Java reflection can't.

Why does Scala place a dollar sign at the end of class names?

In Scala when you query an object for either its class or its class name, you'll get a rogue dollar sign ("$") at the tail end of the printout:
object DollarExample {
def main(args : Array[String]) : Unit = {
printClass()
}
def printClass() {
println(s"The class is ${getClass}")
println(s"The class name is ${getClass.getName}")
}
}
This results with:
The class is class com.me.myorg.example.DollarExample$
The class name is com.me.myorg.example.DollarExample$
Sure, it's simple enough to manually remove the "$" at the end, but I'm wondering:
Why is it there?; and
Is there anyway to "configure Scala" to omit it?
What you are seeing here is caused by the fact that scalac compiles every object to two JVM classes. The one with the $ at the end is actually the real singleton class implementing the actual logic, possibly inheriting from other classes and/or traits. The one without the $ is a class containing static forwarder methods. That's mosty for Java interop's sake I assume. And also because you actually need a way to create static methods in scala, because if you want to run a program on the JVM, you need a public static void main(String[] args) method as an entry point.
scala> :paste -raw
// Entering paste mode (ctrl-D to finish)
object Main { def main(args: Array[String]): Unit = ??? }
// Exiting paste mode, now interpreting.
scala> :javap -p -filter Main
Compiled from "<pastie>"
public final class Main {
public static void main(java.lang.String[]);
}
scala> :javap -p -filter Main$
Compiled from "<pastie>"
public final class Main$ {
public static Main$ MODULE$;
public static {};
public void main(java.lang.String[]);
private Main$();
}
I don't think there's anything you can do about this.
Although all answer that mention the Java reflection mechanism are correct this still doesnot solve the problem with the $ sign or the ".type" at the end of the class name.
You can bypass the problem of the reflection with the Scala classOf function.
Example:
println(classOf[Int].getSimpleName)
println(classOf[Seq[Int]].getCanonicalName)
=> int
=> scala.collection.Seq
=> Seq
With this you just have the same result as you have in for example Java
There are several problems with your approach:
You are using Java Reflection. Java Reflection doesn't know anything about Scala.
Furthermore, you are using Java Reflection on a Singleton Object, a concept that doesn't even exist in Java.
Lastly, you are using Java Reflection to ask for the class of a Singleton Object, but in Scala, Singleton Objects aren't instances of a class.
So, in other words: you are asking the wrong language's reflection library to reflect on something it doesn't understand and return something that doesn't even exist. No wonder you are getting nonsense results!
If you use Scala Reflection instead, the results become a lot more sensible:
import scala.reflect.runtime.{universe => ru}
def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]
object Foo
val theType = getTypeTag(Foo).tpe
//=> theType: reflect.runtime.universe.Type = Foo.type
As you can see, Scala Reflection returns the correct type for Foo, namely the singleton type (another thing that doesn't exist in Java) Foo.type.
In general, whereas Java Reflection deals mainly in classes, Scala Reflection deals in Types.
Using Scala Reflection instead of Java Reflection is not only better because Java Reflection simply doesn't understand Scala whereas Scala Reflection does (in fact, Scala Reflection is actually just a different interface for calling into the compiler, which means that Scala Reflection knows everything the compiler does), it also has the added benefit that it works on all implementations of Scala, whereas your code would break on Scala.js and Scala-native, which simply don't have Java Reflection.
This is a result of compiling to the JVM. To make an object in scala requires two classes. The "base" class and the class to make the singleton object. Because these classes can't both have the same name, the $ is appended. You could probably modify the compiler so that it won't make a $ but you will still need some way to name the generated class names.

How can I provide a scala companion object's class to Java?

I have a Java code that looks for annotations in static methods of a class.
processor.readStatics( MyClass.class ); // Takes Class<?>
How can I provide the methods of a scala companion object to this function from within scala?
class MyClass {
}
object MyClass {
def hello() { println("Hello (object)") }
}
I seems that:
MyClass$.MODULE$.getClass()
should be the answer. However, MyClass$ seems to be missing from scala (in 2.10, at least) and only visible to Java.
println( Class.forName("MyClass$.MODULE$") )
also fails.
Class name is MyClass$ (with the appropriate package name prepended).
println(Class.forName("MyClass$")) will print out "class MyClass$".
MyClass$.MODULE$ is the instance of the class, referencing the singleton object.
println(MyClass$.MODULE$ == MyClass) will print out "true" even though, when compiling, you will get a warning that this comparison always yields false :)
Note, that none of this works in repl for some reason. You need to actually create a .scala file, compile it with scalac, and run.
So, in java, use MyClass$ to reference the class of MyClass object statically, use MyClass$.MODULE$ to reference the singleton instance of MyClass object, use MyClass$.class or MyClass$.MODULE$.getClass() to reference the class of the singleton object dynamically, use Class.forName("MyClass$") to access it at runtime by name.
The shortest and type-safest solution is to simply use
MyClass.getClass
I would have hoped the following to work, but apparently scalac is not happy with it:
classOf[MyClass.type]

How do I access Java enums from Scala?

My java class is as follows
public class Test {
protected enum TestEnum {A, B, C};
public Test(TestEnum te) {
}
}
here is my Scala
class ScalaEnum(myEnum: TestEnum) extends Test(myEnum) {
}
I receive the following error message
class TestEnum in object Test cannot be accessed in object Test Access to protected class TestEnum not permitted because enclosing class class ScalaEnum in package XXX is not a subclass of object Test in package YYY where target is defined
As #Alex and #Jean-Phillipe said, this has not much to do with the fact that you're trying to access an enum and more to do with the fact that inner-class enums are implicitly static: see this answer, for example.
That means that you're running up against this limitation. Changing TestEnum to be public works around the problem for me with Scala 2.9.1.
Having said all that, despite Martin's vehement objections to removing the limitation, your code works as expected with Scala 2.10.
It sounds like the enum class is implicitly static, because Scala calls it "object Test". Try qualifying it in the constructor (e.g. Test.TestEnum), and if that doesn't work, relaxing the visibility to package access might.