Direct class references in Scala?

I ran into a standard problem as a newbie to Scala: how can I define two classes so that I can instantiate one of them as a member variable, which in turn points to the first instance?

I would like to end an instance of a game that is a member of type Dealer which has a member of type Game, which is actually the original instance of the game

So, in this case, each instance (Game, Dealer) has a member, which is another instance. Can someone lead me to the right path to this?

+6
scala
source share
3 answers

If you really need the classes to be immutable, the only option is to use the name parameters in the constructor and always instantiate like lazy val s:

 class Dealer(val name: String, g: => Game) { lazy val game = g override def toString = "Dealer(name=%s, game=%s)".format(name, game.name) } class Game(val name: String, d: => Dealer) { lazy val dealer = d override def toString = "Game(name=%s, dealer=%s)".format(name, dealer.name) } lazy val game: Game = new Game("Doppelkopf", new Dealer("Peter", game)) lazy val dealer: Dealer = new Dealer("Tina", new Game("Poker", dealer)) 

Note that you need a caption type for lazy vals or it won’t compile.

+8
source share

Here you have two options:

  • Make your objects mutable, and then just use the same methods as in Java.
  • Make them immutable, and then discard the two-way dependencies.

To understand why, consider the following conversion between (immutable) trees. They are both defined with each parent node containing a list of child nodes, but the children do not know their parent:

 a (a) b (b) cc d --> (d) ee ff gg 

In particular, node d was cloned with a new value. To do this, we also had to clone all the parent nodes (shown in brackets).

If the nodes held their parent, then c need to be "updated" to reflect the new b node, and e, f, g would need to be updated to reflect the new a node, i.e. you will need to copy the whole tree!

Only by maintaining relationships in one direction, from parent to child, does it become possible to reuse c, e, f, g for successive versions of the structure. This is a powerful optimization and the key to writing effective functional algorithms.

+3
source share

I think you are talking about a β€œtwo-way” dependency, and this is easy to do if max one of the objects is immutable (if you want both to be immutable, you should see Moviz's solution).

In my example, I allow Game be an immutable entity. The dealer may not participate in the game.

 class Dealer(val name: String){ var game: Option[Game] = None } case class Game(name: String, dealer: Dealer) // Instanciate the game and the dealer val olle = new Dealer("Olle") val ollesGame = Game("Olles Game", olle) olle.game = Some(ollesGame) 
+2
source share

All Articles