Reputation: 6039
Is there a way to share a variable among all objects (instantiated from the same type)? Consider the following simple program. Two objects name
and name2
have the same type A
. Is there way to connect the properyList
inside the two instantiation name
and name2
?
class A {
var properyList = List[String]()
def printProperties(): Unit = {
println(properyList)
}
}
object Experiment {
def main(args: Array[String]): Unit = {
val name = new A
val name2 = new A
name.properyList = List("a property")
name.printProperties()
name2.printProperties()
}
}
The output is
List(a property)
List()
Any way to change the class definition so that by just changing the .properyList
in one of the objects, it is changed in all of the instatiations?
Upvotes: 4
Views: 4376
Reputation: 14404
What you seem to be looking for is a class variable. Before I get into why you should avoid this, let me explain how you can do it:
You can attach propertyList to the companion object instead of the class:
object A {
var properyList = List[String]()
}
class A {
def printProperties(): Unit = {
println(A.properyList)
}
}
Now, to the why you shouldn't:
While scala let's you do pretty much anything that the JVM is capable of, its aims are to encourage a functional programming style, which generally eschews mutable state, especially shared, mutable state. I.e. the anti-pattern in A
is not only that propertyList is a var
, not a val
but by sharing it via the companion object, you further allow anyone, from any thread to change the state of all instances at anytime.
The benefit of declaring your data as val
is that you can safely pass it around, since you can be sure that nobody can change from under you at any time in the future.
Upvotes: 10
Reputation: 12563
Based on Arne Claassen's answer, but using private mutable collection with the companion object, which makes it visible only to the companion classes. Very simplistic example tried out in scala 2.11.7 console:
scala> :paste
// Entering paste mode (ctrl-D to finish)
object A {
private val mp = scala.collection.mutable.Map("a"->1)
}
class A {
def addToMap(key:String, value:Int) = { A.mp += (key -> value) }
def getValue(key:String) = A.mp.get(key)
}
// Exiting paste mode, now interpreting.
defined object A
defined class A
// create a class instance, verify it can access private map in object
scala> val a = new A
a: A = A@6fddee1d
scala> a.getValue("a")
res1: Option[Int] = Some(1)
// create another instance and use it to change the map
scala> val b = new A
b: A = A@5e36f335
scala> b.addToMap("b", 2)
res2: scala.collection.mutable.Map[String,Int] = Map(b -> 2, a -> 1)
// verify that we cannot access the map directly
scala> A.mp // this will fail
<console>:12: error: value mp is not a member of object A
A.mp
^
// verify that the previously created instance sees the updated map
scala> a.getValue("b")
res4: Option[Int] = Some(2)
Upvotes: 0
Reputation: 7152
You seem to be looking for something like java static fields.
In scala you usually achieve something like that by using a companion object:
object Main extends App {
class A {
import A._
def printProperties(): Unit = {
println(properyList)
}
}
object A {
private var properyList = List[String]()
def addProperty(prop: String): Unit = {
properyList ::= prop
}
}
val name = new A
val name2 = new A
A.addProperty("a property")
name.printProperties()
name2.printProperties()
}
Upvotes: 4
Reputation: 2069
If you want to have something similar to java's static fields you will have to use companion objects.
object Foo {
private var counter = 0
private def increment = {
counter += 1;
counter
}
}
class Foo {
val i = Foo.increment
println(i)
}
Code copied from: "Static" field in Scala companion object
http://daily-scala.blogspot.com/2009/09/companion-object.html
Upvotes: 2