This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

Accessing parent objects in CLOS

8 posts · 6441 views

I was wondering what is the best way to access the parent of an object.
Is there a way to access the parent through the child object?

For example, imagine a simple game where by if a ball is in a certain position
(eg the goal) a goal is scored and the score for that game is updated.
Imagine also that the score is dependent on the size of the ball.
So a ball of size 3 gives you 3 points.
A ball of size 8 gives you 8 points etc.

Each game object has a ball object.
(defclass game ()
  (score        :initform 0 :accessor game-score)
  (game-ball    :initform (make-instance 'ball)))

(defclass ball ()
  (size :initform 1 :accessor ball-size))

(defmethod move-ball (ball x y)
  (if (ball-is-in-goal-p x y)
      <update-score>
      (move-ball-as-normal)))
It's the <update-score> part I'm having trouble with.

I realize there are various things I could do
like make the ball a global variable or make the move-ball method accept
a game object. However is there something equivalent to
ball.parent.score?

Re: Accessing parent objects in CLOS

jsmcgd wrote:I was wondering what is the best way to access the parent of an object.
Is there a way to access the parent through the child object?
There is no way to do this automatically. You need to give the child a reference to its parent when it's created. Then you can access the parent through the child just like you can access the child through the parent.
Cheers, Dave
Slowly but surely the world is finding Lisp. http://www.findinglisp.com/blog/

Re: Accessing parent objects in CLOS

Cheers.

Is this the accepted way or should I ideally be changing my architecture so I don't run into this problem too often?

Perhaps I should get cracking on AMOP?

Re: Accessing parent objects in CLOS

If there is only going to be one game object, you could use a global variable.

Also, in your move-ball method, I think it would be better to dispatch when the ball variable is a subtype of ball instead of T.

Re: Accessing parent objects in CLOS

If I do decide to make a reference to the game object in the ball object,
how would one do this? Without a concept like this like you would
have in Java *shudder* how would you pass a reference to a parent object
to a child object when you haven't finished instantiating the parent object?

Use a factory or something? Its beginning to seem a bit kludgesque.

Re: Accessing parent objects in CLOS

jsmcgd wrote:Without a concept like this like you would
have in Java ...
But there is such a concept:
(defclass game ()
  ((score        :initform 0 :accessor game-score)
   (game-ball    :accessor game-ball)))

(defmethod initialize-instance :after ((game game) &rest args)
  (declare (ignore args))
  (with-slots (game-ball) game
    (setq game-ball (make-instance 'ball :game game)))
initialize-instance's first argument sure looks a lot like a this reference to me. Yes, :initform is convenient, but it works for a certain class of special cases only. For more general needs, there's nothing wrong about adding a method to initialize-instance, i.e. defining a constructor as you would in Java.

Re: Accessing parent objects in CLOS

There isn't any built-in CLOS concept of "parent" or "child" in the
sense in which you mean it. If your model is that there are games and
balls, and there's a one-to-one relationship between them, you's model
that using slots. The game would have a slot set to the ball object,
and vice versa. Then move-ball would access its "game" slot, using an
:accessor (or :reader, or with-slots, whatever), to get its hands on
the game object.

Re: Accessing parent objects in CLOS

jsmcgd wrote:I realize there are various things I could do
like make the ball a global variable or make the move-ball method accept
a game object. However is there something equivalent to
ball.parent.score?
This isn't really possible... when you say 'parent', I think you just mean 'client' - by using the ball, the game class is a client of the ball class. But remember that any number of different objects can share a reference to the same ball. So if there was such a thing as ball.clients, it would return a set of objects which refer to the ball. Which isn't very helpful, of course. :)
What's usually done (at least in Java, C++ and the like, since I don't have experience with CLOS yet) is for the game to either pass a reference to 'this' (which doesn't seem to exist in CLOS?) to the ball, or perhaps to register a callback function defined by the game class with the ball object that should be called on certain events.