Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

forward class references in Scala?

Tags:

scala

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?

like image 623
Tim Converse Avatar asked Oct 31 '10 04:10

Tim Converse


People also ask

What is forward reference pointer?

Forward reference is when you declare a type but do not define it. It allows you to use the type by pointer (or reference for C++) but you cannot declare a variable. This is a way to say to the compiler that something exists. Say that you have a Plop structure defined in Plop.

What is forward reference in programming?

A forward reference occurs when a label is used as an operand, for example as a branch target, earlier in the code than the definition of the label. The assembler cannot know the address of the forward reference label until it reads the definition of the label.

Is a forward reference extends over the definition of?

0. forward reference extends over definition of variable.

Are forward references allowed in Java?

Java allows very flexible forward references. A method may refer to a variable or another method of its class, regardless of where in the current class the variable or method is defined.


2 Answers

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.

like image 199
Moritz Avatar answered Oct 19 '22 05:10

Moritz


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.

like image 36
Kevin Wright Avatar answered Oct 19 '22 03:10

Kevin Wright