Say in a scala file I define a class like
private class Test{}
what does the private here mean? In java you can't have a top level private class, which obviously makes sense. But private is syntactically valid in scala, hope someone can shed some light upon it.
You could specify package name for private modifier to allow access to this class only from specified package. By default (without package specified) it is visible only for other members in the enclosing package.
$ cat > test.scala <<EOF
package myPackage {
private[myPackage] class Test
private object A extends Test
}
package otherPackage {
object B extends myPackage.Test
}
EOF
$ scalac test.scala
test.scala:7: error: class Test in package myPackage cannot be accessed in package myPackage
object B extends myPackage.Test
^
one error found
For instance you can access private class from its companion object like this:
trait ITest
private class Test extends ITest
object Test {
def apply(): ITest = new Test
}
Test()
// ITest = Test#59e2abc3
Further clarification on examples:
package myPackage {
private class Test
private object A extends Test
object B extends myPackage.Test //Compile error: private class Test escapes its defining scope as part of type myPackage.Test
private object C extends myPackage.Test // works since C is also private
object Test {
def apply() = new Test //error: private class Test escapes its defining scope as part of type myPackage.Test
}
object Test2 {
def apply(): ITest = new Test //works as ITest is public
}
}
As long as instances of a private class do not escape the enclosing package scope it can be used within the package hierarchy. Companion objects accessing private classes has to be in same package hierarchy as well. With private[P] - p can be any package name that exists.
Related
I am having a hard time understanding Private[this] when this Bind to a package vs Private[PackageName]
E.g.
This works fine:
package scopeA {
private[scopeA] class PrivateClass1
class PrivateClass2 extends PrivateClass1
}
But this does not
package scopeA {
private[this] class PrivateClass1
class PrivateClass2 extends PrivateClass1 //private class PrivateClass1 escapes its defining scope as part of type scopeA.PrivateClass1
}
However if i modify the second one as such:
package scopeA {
private[this] class PrivateClass1
private class PrivateClass2 extends PrivateClass1
}
private[this] or private, have the same effect in the last scenario.
I can see the difference, but i can't put proper words on it. Hence my question, what is the meaning of Private[this] when this bind to a package ? and is it different from private[PackageName], what's the exact difference between the two ?
There is something about escaping the scope that i am not sure to follow, why would it be ok with package name but not this ?
this refers to (possible) package object
package com {
package object example {
implicitly[this.type =:= com.example.`package`.type]
}
}
According to the Scala Language Specification, packages are AnyRef values and have types. How does this make sense?
I have a class that contains a main method, and I wish to start a new process that runs this class.
But when I try to use Scala to get the name of this class, it gives me the wrong name. For example:
object Test {
def main(args: Array[String]) = {
println(Test.getClass.getCanonicalName)
}
}
Then:
roei#roei-main:~/Java$ scalac Test.scala
roei#roei-main:~/Java$ scala Test
Test$
roei#roei-main:~/Java$ javap Test*.class
Compiled from "Test.scala"
public final class Test {
public static void main(java.lang.String[]);
}
Compiled from "Test.scala"
public final class Test$ {
public static final Test$ MODULE$;
public static {};
public void main(java.lang.String[]);
}
Test.getClass.getCanonicalName gives me Test$, not Test. But the static main method is inside of a class named Test, whereas Test$ contains a non-static main. Obviously I can do the workaround of just deleting the $ at the end, but I'm looking for a more satisfying/reliable solution.
A possible solution would be using ClassTag of scala.reflect (see API). I mean something like the following:
import scala.reflect.ClassTag
import scala.reflect.classTag
class Test
object Test {
def main(args: Array[String]) = {
println(Test.getClass.getCanonicalName)
println(classTag[Test].runtimeClass.getCanonicalName)
}
}
it will print:
Test$
Test
I have read this article to better understand Scala scoping rules.
Everything seemed clear until I ran into some code on GitHub that was like this:
package x.y.z
private[z] class ExampleClass {
// class body
}
As you can see, we have a private top-level class, and there's an access qualifier to modify the scope of that class, but it's set to the very same package where the class is defined. If the access qualifier was set to an enclosing scope (e.g. package y) I would perfectly get it, but like this I can't understand the difference with simply declaring the class as private:
package x.y.z
private class ExampleClass {
// class body
}
So what is the difference between the two snippets posted above?
NOTE: I don't know if it's of any relevance, but in the same file a companion object for the class was defined and simply declared as private (with no access qualifiers).
In the example you provided both modifiers have the same effect. Difference would be more apparent if you had an enclosing class/object.
Compiles:
package x.y.z
object OuterExampleClass {
private[z] class ExampleClass()
}
object AnotherObject {
val ec = new OuterExampleClass.ExampleClass()
}
Fails to compile:
package x.y.z
object OuterExampleClass {
private class ExampleClass() // no [z] !!!
}
object AnotherObject {
val ec = new OuterExampleClass.ExampleClass() // error
}
with message:
class ExampleClass in object OuterExampleClass cannot be accessed in
object x.y.z.OuterExampleClass
Given a class like:
class MyClass {
protected object MyObj { ... }
}
is it possible to write a trait that will permit exposing MyObj. E.g. with inheritance I could do the following:
class TestMyClass extends MyClass {
val getMyObj = MyObj
}
but I want to do this via a trait, something like the following which doesn't typecheck:
trait ExposeMyObj {
val getMyObj = MyObj // super.MyObj/this.MyObj don't work
}
and use it like:
class TestMyClass extends ExposeMyObj
Is it possible to reproduce the functionality in TestMyClass into a trait to expose the protected object, and if so how?
If you know that your trait will always be mixed in to an instance of MyClass (or a subclass), you can enforce the expectation with a self-type, and then access the object:
trait ExposeMyObj {
self: MyClass =>
val getMyObj = MyObj
}
Edit: an example of using this trait:
class TestMyClass extends MyClass with ExposeMyObj
val test = new TestMyClass
test.getMyObj // accesses MyObj defined in MyClass.
Edit 2: attempting to address #jbrown's comment (re: testing queries within repos) - I would look at doing something like the following - first, in each repo's file, add a trait for each repo holding the queries for that repo:
trait UserQueries { // you could look at making this protected, if you like
protected def query1(param: String) = List(param) // very silly implementation, but hopefully enough to make the point
... // other queries
}
class UserRepo extends UserQueries // Has (internal) access to those queries
Then in the test class file for a given repo:
class UserQueriesTester extends UserQueries with ScalaTest { // or whatever test framework you are using
// (public) tests to run - eg:
def testQuery1 = query1("test") should be (List("test"))
}
In Scala, if I create an object and companion class, identifiers declared with the protected modifier can be accessed from the class if the object is imported:
object Foo {
protected val X = 42
}
class Foo {
import Foo._
def getX(): Int = X
}
However, the protected identifier cannot be accessed from a subclass of the class Foo:
class Bar extends Foo {
import Foo._
def getX(): Int = X * 2
}
I get a compile-time error in Bar.
Other then (implied) public, is there any access modifier I can place on X so that it can be accessed from subclasses of its companion, but not from other classes, including other classes in the same package?
That's because only the class Foo is companion to the object Foo.
Here, the difference between private and protected meaningless, since the object Foo is a singleton, which means there isn't any other object that has the same class as object Foo (Foo.type).
Access restriction in Scala is package-based, so the short answer is no. You could make a forwarder on the base class, though, unless you need it to be available without an instance.
In your place, however, I'd go back to the design board.
In such cases, I would suggest using a package private modifier, like below:
object Foo {
private[your_package] val X = 42
}
The value will still be visible to everybody else in the package.
To achieve the same thing, One solution to this problem can be:
class Bar extends Foo {
import Foo._
override def getX(): Int = super.getX * 2
}