4

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?

2
  • This is the publish-subscribe pattern. Commented Sep 14, 2015 at 19:41
  • I think in this example companion object would be better. Commented Sep 14, 2015 at 19:44

4 Answers 4

10

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.

Sign up to request clarification or add additional context in comments.

1 Comment

As a modification, you can declare properyList private, that would allow only the companion class to access it.
4

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()
}

Comments

2

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

Comments

0

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.