What's the scope of a private top-level class with access qualifier set to the same package where the class is defined in Scala? - scala

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

Related

Make constructor parameters public in subclass

I want the protected fields of a class to be made publicly visible in a subclass:
class MyClass(protected val someDao: SomeDao)
class TestMyClass extends MyClass(mock[SomeDao])
Now I want to access someDao like so:
val testClass = new TestMyClass
testClass.someDao
I've read that in Java and Scala access modifiers can be broadened but not restricted in subclasses (although these are just constructor parameters, not private fields per se). How can I achieve that in this example?
EDIT:
The answers provided suggest making someDao public in the base class. This is not what I want. I want it to remain private, but just change its visibility to public in the TestMyClass class.
As far as I know, an overriden val cannot access the super implementation.
If you can modify the base class, one solution is to explicitely define an accessor method, which can be overriden; something like this:
class MyClass(_someDao: SomeDao) {
protected def someDao = _someDao
}
class TestMyClass extends MyClass(mock[SomeDao]) {
override def someDao = super.someDao
}
If you cannot change the base class, one workaround would be to define a public accessor method with a different name:
class MyClass(protected val someDao: SomeDao)
class TestMyClass extends MyClass(mock[SomeDao]) {
def someDao2 = someDao
}
Add var or val to parameters declaration:
class MyClass(val someDao: SomeDao)
In this case only getter function will be generate for someDao field. So when you write testClass.someDao you retrieve not the someDao as field you use their getter function.
Good example about visibility of class parameters in Scala demostrated at this article.
Regarding to your last updates
Set package scope for parameter declaration:
class MyClass(private[lastPackageOfSomeDao] val someDao: SomeDao)

companion object to a private class: why isn't it valid?

i needed two instances that has access to each other privates. i naturaly thought of a companion object that grants access to a one and only instance of it's companion class. the class itself i made private, so users cannot just create instances using new.
object A {
def apply = dual
lazy val dual = new A
}
private class A {
//some irrelevant logic...
}
this code does not compile. i get: class A escapes its defining scope as part of type A error, which i don't really understand. my current workaround was to define a trait with every method declaration the class should have and make class A extend that trait, while dual is of the trait type, and not class A type.
what's the theoretic problem i'm missing here? why is this forbiden?
Paolo's solution is good (+1), but he didn't explain the error message, so let me try that. The problem stems from the fact that every method needs a return type. Your original definition of apply and dual returned an object of class A, thus the implicit return type of both was A. That implies that A must be visible to clients - how else could they call the function or access the val? Moreover, as both - and their parent object too - are public, they are globally visible. However, you declared A private which means it must not be visible outside its package. So there is a conflict which can't be resolved by the compiler.
The general rule is that all parameter and return type of functions / members must have (at least) the same scope of visibility as the referring member itself*. Thus one trivial way to solve this problem would be to reduce the visibility of apply and dual to private. This would satisfy the compiler, but not you :-)
Your solution gets around the problem by changing the static return type to a public trait, which thus has the same visibility as the members referring to it. The dynamic type of the returned object is still class A, however, this need not be visible to clients. This is a classic example of the principle "program to interfaces, not implementations".
Note that to apply this principle to the full extent, one could turn class A into a private inner class of object A, thus making it innaccessible even for other classes within the same package:
trait A {
//...
}
object A {
def apply: A = dual
lazy val dual: A = new AImpl
private class AImpl extends A {
//some irrelevant logic...
}
}
* To be pedantic, the enclosing class / object may reduce the visibility of its members, like here:
private class Holder {
def member = new Hidden
}
private class Hidden
where member is public but its enclosing class is private, effectively hiding its members from the external world. So the compiler emits no complaints here.
I think you don't want a private class, but a class with a private constructor.
class A private()
object A {
def apply = dual
lazy val dual = new A
}
Now your class is "visible" to outside code, but only your companion object can create instances of it.

Class of current static scope in scala

I'm currently constructing loggers (with configgy) like this:
class MyClass {
private val log = Logger.get(classOf[MyClass])
}
I would like to avoid repeating "MyClass" as in classOf[MyClass] (for example I want to quickly copy paste the log definition line, without smart IDE expanding the template with the class name), but I don't want to use the dynamic class of the current object, like:
class MyClass {
private val log = Logger.get(this.getClass)
}
EDIT: because this way instances of subclasses will have the subclass class object passed to the parent logger:
class MyClass {
private val log = Logger.get(this.getClass)
def doit = log.info("doing")
}
class SubClass extends MyClass {
}
new SubClass().doit
will use the logger configured for SubClass, not MyClass as I want.
Is there a way to have some fixed expression which somehow yields the class which is being defined at that point?
The short answer is that Scala doesn't have a way to do that. The long answer is that you can do it, but it's an ugly hack. The hack is to use the fact that exception stack traces include the name of the static class definition where the stack trace was created. Parse and tada. But, seriously, don't do this. Or, if you do, move it to a mixin trait and modify the parsing bit to pull the class name from the appropriate spot in the trace. Also, I've only tested this in some fairly limited conditions: no guarantee that it will work everywhere.
class MyClass {
private val log = Logger get (Class forName (
new RuntimeException().getStackTrace.apply(0).toString takeWhile
(_ != '(') split "\\." dropRight 1 mkString "."))
def doit = log.info("doing")
}
Surely you can just use the protected access modifier and access it directly?
class MyClass {
protected val log = Logger.get(classOf[MyClass])
}
class SubClass extends MyClass {
}
new SubClass().doit

Scala protected object

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
}

Private and protected constructor in Scala

I've been curious about the impact of not having an explicit primary constructor in Scala, just the contents of the class body.
In particular, I suspect that the private or protected constructor pattern, that is, controlling construction through the companion object or another class or object's methods might not have an obvious implementation.
Am I wrong? If so, how is it done?
You can declare the default constructor as private/protected by inserting the appropriate keyword between the class name and the parameter list, like this:
class Foo private () {
/* class body goes here... */
}
Aleksander's answer is correct, but Programming in Scala offers an additional alternative:
sealed trait Foo {
// interface
}
object Foo {
def apply(...): Foo = // public constructor
private class FooImpl(...) extends Foo { ... } // real class
}