Does writing private[this] def
make sense in terms of performance-to-noise ratio compared to just private def
? I understand it makes a difference regarding private[this] val
over private val
because the former allows scalac to create an actual field. But perhaps for def
it makes no difference? Finally, how about private[this] var
?
There is a very similar question, but it does not contain specific statements regarding performance.
When a method is private it means it can only be accessed by objects OF THE SAME CLASS.
In Scala,private[this] is object private,which makes sure that any other object of same class is unable to access private[this] members.
The rule is that a method should be made provided unless it is needed. One of the main reasons for this is that in a future release of an API etc., you can always make a private function public, but you can almost never make a previous public function private without breaking existing code. Save this answer.
In Scala, a private top-level class is also accessible from nested packages. This makes sense, since the enclosing scope of both the private class and the nested package is the same (it's the package inside which both are defined), and private means that the class is accessible from anywhere within its enclosing scope.
No, there isn't any performance advantage. Both private def
and private[this] def
are translated to private
or public
methods in bytecode depending on whether they are called from a different class, not depending on what their visibility in Scala is.
Let's start with what the Scala language specification says about private[this]
:
it can be accessed only from within the object in which it is defined. That is, a selection p.M is only legal if the prefix is this or O.this, for some class O enclosing the reference. In addition, the restrictions for unqualified private apply.
You can see that the specification just says what is syntactically acceptable or not. Both private
and private[this]
can be only called from the instances of the same class or inner classes. In bytecode, you can only differentiate access on the class level, not an instance level. Therefore both options should be the same in bytecode and Scala enforces the difference only during compilation.
First, let's look at a simple example:
class MyClass {
private def privateDef(x: Int) = x
private[this] def privateThisDef(x: Int) = x
}
This is translated to bytecode as
public class MyClass {
private int privateDef(int);
private int privateThisDef(int);
public MyClass();
}
As you can see, both methods end up as private
, therefore there is no difference from the JVM point of view (e.g. regarding inlining, static/dynamic binding, etc.).
How does this change when we add inner classes?
class MyClass {
private def privateDef(x: Int) = x
private[this] def privateThisDef(x: Int) = x
class MyInnerClass{
MyClass.this.privateDef(1)
MyClass.this.privateThisDef(2)
}
}
This gets translated to
public class MyClass {
public int MyClass$$privateDef(int);
public int MyClass$$privateThisDef(int);
public MyClass();
}
public class MyClass$MyInnerClass {
public final MyClass $outer;
public MyClass MyClass$MyInnerClass$$$outer();
public MyClass$MyInnerClass(MyClass);
}
You can see that this time, both methods in MyClass
are public so that the inner class can call them. Again, no difference between private
and private[this]
.
Scala adds one more special case when a private method can be called from a different class - when you call a private method from a companion object in its respective class. A companion object for MyClass
would be a separate class named MyClass$
in bytecode. Calling a private
method in companion crosses class boundaries and therefore such method will be public in bytecode.
You can't call private[this]
method outside companion, but this is just a syntactical restriction. Wherever you can choose between private
and private[this]
, the result will be the same in bytecode.
The behavior for vars seems to be somewhat different then for defs. This class
class MyClass {
private var privateVar = 0
private[this] var privateThisVar = 0
private var privateVarForInner = 0
private[this] var privateThisForInner = 0
class MyInnerClass{
privateVarForInner = 1
privateThisForInner = 1
}
}
is compiled to
public class MyClass {
private int privateVar;
private int privateThisVar;
private int MyClass$$privateVarForInner;
public int MyClass$$privateThisForInner;
// ...
}
The inner class then uses setter for privateVar
and field access for privateThisVar
. I'm not sure why scalac behaves this way, I haven't find anything in the spec. Perhaps it's something implementation-specific.
Edit: Upon request, I created a small JMH benchmark comparing the performance of getting and setting a private var
and private[this] var
. The result? All operations are ≈ 10⁻⁸
s according to JMH. The difference is negligible and the the case with inner classes and var
s is rare anyway.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With