'private[this] vs private
In Scala I see such feature as object-private variable. From my not very rich Java background I learnt to close everything (make it private) and open (provide accessors) if necessary. Scala introduces even more strict access modifier. Should I always use it by default? Or should I use it only in some specific cases where I need to explicitly restrict changing field value even for objects of the same class? In other words how should I choose between
class Dummy {
private var name = "default name"
}
class Dummy {
private[this] var name = "default name"
}
The second is more strict and I like it but should I always use it or only if I have a strong reason?
EDITED: As I see here private[this]
is just some subcase and instead of this
I can use other modifiers: "package, class or singleton object". So I'll leave it for some special case.
Solution 1:[1]
I don't think it matters too much, since any changes will only touch one class either way. So the most important reason to prefer private
over protected
over public
doesn't apply.
Use private[this]
where performance really matters (since you'll get direct field access instead of methods this way). Otherwise, just settle on one style so people don't need to figure out why this property is private
and that one is private[this]
.
Solution 2:[2]
There is a case where private[this]
is required to make code compile. This has to do with an interaction of variance notation and mutable variables. Consider the following (useless) class:
class Holder[+T] (initialValue: Option[T]) {
// without [this] it will not compile
private[this] var value = initialValue
def getValue = value
def makeEmpty { value = None }
}
So this class is designed to hold an optional value, return it as an option and enable the user to call makeEmpty
to clear the value (hence the var). As stated, this is useless except to demonstrate the point.
If you try compiling this code with private
instead of private[this]
it will fail with the following error message:
error: covariant type T occurs in contravariant position in type Option[T] of value value_= class Holder[+T] (initialValue: Option[T]) {
This error occurs because value is a mutable variable on the covariant type T (+T) which is normally a problem unless marked as private to the instance with private[this]
. The compiler has special handling in its variance checking to handle this special case.
So it's esoteric but there is a case where private[this]
is required over private
.
Solution 3:[3]
private var name
is accessible from any method of the class Dummy
(and its companion object Dummy
).
private[this] var name
is accessible from methods of this
object only, not from other objects of class Dummy
.
Solution 4:[4]
private[this] (equivalent to protected[this]) means that that "y" is only visible to methods in the same instance. For example, you could not reference y on a second instance in an equals method, i.e., "this.y == that.y" would generate a compilation error on "that.y". (source)
so you can do private[this] every time you want but you can have some problem if you need refer it
Solution 5:[5]
This was tested using scala 2.11.5. Consider the code below
class C(private val x: Int) {
override def equals(obj: Any) = obj match {
case other: C => x == other.x
case _ => false
}
}
println(new C(5) == new C(5)) //true
println(new C(5) == new C(4)) //false
it will compile and work as this java (1.8) code
class C {
private int x;
public C(int x) {
this.x = x;
}
public boolean equals(Object obj) {
if (obj instanceof C) {
return ((C) obj).x == x;
}
else {
return false;
}
}
}
System.out.println(new C(5).equals(new C(5))); //true
System.out.println(new C(5).equals(new C(4))); //false
however if you use '[this]' modifier the code below won't compile
class C(private[this] val x: Int) {
override def equals(obj: Any) = obj match {
case other: C => this.x == other.x //problem is here
case _ => false
}
}
This is because in the first case 'x' is accessible on class level, whereas in the second case is it more strict instance level. It means that 'x' can be accessed only from the instance to which it belongs. So 'this.x' is fine but 'other.x' is not.
You can refer to section 13.5 of "Programming in Scala: A Comprehensive Step-By-Step Guide" book for more details about access modifiers.
Solution 6:[6]
In most OOP programming language like java, private fields/methods mean that these private fields/methods are not accessible outside from the class. However, instances/objects of same class can have access to the private fields of objects using assignment operator or by means of copy constructor. In Scala,private[this] is object private,which makes sure that any other object of same class is unable to access private[this] members.
Example
1.Without private[this]
object ObjectPrivateDemo {
def main(args: Array[String]) {
var real = new User("realUserName", "realPassword")
var guest = new User("dummyUserName", "dummyPassword")
real.displayUser(guest)
}
}
class User(val username:String,val password:String) {
private var _username=username
private var _password=password
def displayUser(guest:User){
println(" guest username="+guest._username+" guest password="+guest._password)
guest._username= this._username
guest._password= this._password
println(" guest username="+guest._username+" guest password="+guest._password)
}
}
2.Using private[this]
class User(val username: String, val password: String) {
private var _username = username
private[this] var _password = password
def displayUser(guest: User) {
println(this._username)
println(this._password)
guest._username = this._username
// for guest._password it will give this :error value _password is not member of class User
guest._password = this._password
}
}
Hence private[this] makes sure that _password field is only accessible with this.
Solution 7:[7]
To elaborate on the performance issue Alexey Romanov has mentioned, here are some of my guesses. Quotes from book "Programming in Scala: A Comprehensive Step-by-Step Guide, 2nd Edition" Section 18.2:
In Scala, every var that is non-private member of some object implicitly defines a getter and a setter method with it.
To test it out, this code will cause compilation error:
class PrivateTest{
var data: Int = 0
def data_=(x : Int){
require(x > 0)
data = x
}
}
Scala complains about error: ambiguous reference to overloaded definition
. Adding override keyword to data_=
won't help should prove that the method is generated by the compiler. Adding private
keyword to variable data
will still cause this compilation error. However, the following code compiles fine:
class PrivateTest{
private[this] var data: Int = 0
def data_=(x : Int){
require(x > 0)
data = x
}
}
So, I guess private[this]
will prevent scala from generating getter and setter methods. Thus, accessing such variable will save the overhead of calling the getter and setter method.
Solution 8:[8]
Should I always use it by default? Or should I use it only in some specific cases where I need to explicitly restrict changing field value even for objects of the same class? In other words how should I choose between
It's better to use private[this]
if you plan to synchronize the variable.
Here a good example from the scala style guide of the Spark team:
// The following is still unsafe.
class Foo {
private var count: Int = 0
def inc(): Unit = synchronized { count += 1 }
}
// The following is safe.
class Foo {
private[this] var count: Int = 0
def inc(): Unit = synchronized { count += 1 }
}
Solution 9:[9]
consider the notation of access_modifier[xxx], it indicates scope of it's target:
package demo.mxl
class PrivateThisDemo(private val aField: String, private[this] val bField: String) {
def simpleStr: String = s"aField: $aField, bField: $bField"
}
object PrivateThisDemo {
def main(args: Array[String]): Unit = {
val obj = new PrivateThisDemo("a", "b")
println(s"${obj.simpleStr}")
println(s"${obj.aField}") // compile ok
println(s"${obj.bField}") // compile error, because here out of 'this' scope
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow