tags:

views:

126

answers:

3

I'm running into a standard problem as a newbie to Scala: How do I define two classes in such a way that I can make an instance of one that the other as member variable, which in turn points back to the first instance?

I would like to end up with an instance of Game which has a member of type Dealer which has a member of type Game, which is in fact the original Game instance

So in this case each instance (Game, Dealer) has a member which is the other instance. Can anyone guide me to the right way to to this?

+2  A: 

I think you are talking about a "two way" dependency, and this is easy to do if max one of the entities are immutable (If you want both to be immutable you should see Moviz solution).

In my example I let the Game be the immutable entity. A dealer might not be involved in a 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)
olle kullberg
You can use lazy values and chunks, as shown by Moritz.
Landei
@Landei Thanks. Text is now updated.
olle kullberg
+3  A: 

You have two choices here:

  1. Make your objects mutable, then just use exactly the same techniques as you would in Java.
  2. Make them immutable, then give up the two-way dependencies.

To see why, consider the following transformation between (immutable) trees. These are both defined with each parent node holding a list of child nodes, but children don't know their parent:

a               (a)
  b               (b)
    c                c
    d     -->       (d) 
  e                e
    f                f
    g                g

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

If nodes held their parent, then c would have to be "updated" to reflect the new b node, and e, f, g would have to be updated to reflect the new a node. i.e. the entire tree would have to be copied!

By only holding relationships in one direction, from parent to child, it becomes possible to reuse c, e, f, g across successive versions of the structure. This is a powerful optimisation, and is key to writing efficient functional algorithms.

Kevin Wright
+7  A: 

If you really need to make the classes immutable your only option is to use by name parameters in the constructor and always create instances as lazy vals:

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 the type ascription on the lazy vals or it will not compile.

Moritz
@Moriz Whoa! That is some fancy lines of programming. It just goes to show that everything is possible in Scala.
olle kullberg