The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

Passing an object to its members

Hello, sometimes I've seen code like

ClassY {

    ClassX x;

    public ClassY () {
        ClassX x = new ClassX (this);
    }

}

So basicly we send a reference to "this" object into the newly created object.

In this case a ClassY "has a" ClassX object. But ClassX also ends in a "has a" relation with ClassY.

Isn't this bad in terms of design due to causing a circular reference?

Thanks.
mycode
Thursday, August 09, 2007
 
 
Er, what do you think garbage collection was designed for?

(The main benefit to garbage collection in software is that it handles circular references correctly and automatically.)

Thursday, August 09, 2007
 
 
"Isn't this bad in terms of design due to causing a circular reference?"

Not necessarily. It really depends on what class X actually does with that reference.

For example, consider that class Y has public (or better yet, friend) methods. Class X may want to call those members as part of its own initialization, as in...

public classX( classA ) {
  this.name = classA.getName()
  this.data1 = classA.getData1()
}

This in itself is awkward, yes, but what if you have classes A, B, and C, each of which contain class X?  If A, B, and C all initiate X the same way, it may make more sense to put all of the initialization routines in X, rather than duplicating them in A, B, and C.

This is particularly useful when overloading operators.

Alternatively, what if classX was a collection object? This would be one way of making sure members had a reference to... an associate parent, for lack of a better expression.

As far as design goes, I think it's important to ensure that information is consistently generated and pushed forward from one object as opposed to back and forth. In other words, Y controls the data interfaces to both Y and X. Y modifies both X and Y itself. Ideally, you would never have a situation where you can use both X and Y to modify either X or Y. As long as your consistent and use only one or the other and never both, you would have to go way out of your way to create circular references.
TheDavid
Thursday, August 09, 2007
 
 
"Er, what do you think garbage collection was designed for?"

I always thought it was designed primarily for memory allocation and deallocation. Properly dealing with circular references is just an edge case, and a happy but incidental benefit.

Correct me if I'm wrong.
TheDavid
Thursday, August 09, 2007
 
 
You could eliminate the circular reference by making ClassY an implementation of an abstract base class (interface class). ClassX would be defined to use that interface class in its initialization instead of an object specifically of type ClassY.
dev1
Thursday, August 09, 2007
 
 
I don't see where the circular reference is in the example given?  Is x keeping the reference inside?  And the new x in the ClassY constructor scope is masking the x member.

In any case, there is nothing fundamentally wrong with a circular reference - this example is no worse than a doubly-linked list, is it?

As far as practical usage, sometimes I have child members who need to know their parents (this is very common in the UI space, where a control has a collection of controls and the control base class has a parent reference) and often it is passed at time of construction (for controls, it is usually more dynamic and based on membership in the parent's collection)
Cade Roux Send private email
Thursday, August 09, 2007
 
 
Right on Roux

That reminds me of a Delphi 7 issue. It WON'T let you make a circular reference period. I have ended up with pointers,temp arrays of objects or holding classes too and from UI components in several situations. This is Java I assume?

I see nothing wrong with this, but it could probably be better and more orthodox if it were designed with IOC injection (Spring) or by extending an abstract class. Depends really on the situation.
Richard Corsale Send private email
Thursday, August 09, 2007
 
 
A graph is a normal and well-understood data structure used in many different things. And, oddly enough, it has circular references - a node can refer to another node that refers to another noed that refers to the first node.

The idea that a programming language "forbids" this is rediculous.

You couldn't even have a double-linked list: A <==> B <==> C  -  Every node has a reference to adjacent nodes which also have a reference to all adjacent nodes.

I don't know what Richard means, but if Delphi 7 really forbids double-linked lists, then it's even more stupid than I ever believed possible.


There are technically two "circular references" in the original example: ClassX and ClassY need to know about each other's interfaces, and an instance of ClassX holds a reference to an object of type ClassY, which in turn also holds a reference back to its ClassX owner.

The mutual dependancy is a sign of tight coupling (often a bad idea, but it can be perfectly ok if the two classes form part of a whole module that works together) and the object references either need garbage collection or appropriate ownership management to handle the loop and ensure both objects are deleted correctly.


Typically tight coupling like that is a bad sign - but when it's the right thing to do, it's also the simplest and best option.

Friday, August 10, 2007
 
 
> That reminds me of a Delphi 7 issue. It WON'T let you make > a circular reference period. I have ended up with
> pointers,temp arrays of objects or holding classes too and > from UI components in several situations. "

Yes, (years ago) I ran into that problem too.

(Class B can't have a reference to class A,
if class A already has a reference to class B.)

We fixed this by changing one of the references to TObject,and casting it to the correct class when needed.
(a bit of a hack, but it worked)

If I remember correctly, this could also be fixed by putting both classes within the same unit. (unit = module)

> I don't know what Richard means, but if Delphi 7 really > forbids double-linked lists, then it's even more stupid > than I ever believed possible."

No Delphi doesn't forbid double linked lists.
Delphi forbids circular references to types.
A linked list consists of pointers, so the problem does not occur.
But "double-linking of classes" can be a problem.

But there are workarounds for these situations.
Not Steve Mcconnell Send private email
Friday, August 10, 2007
 
 
Oooopss...
Incorrect use of enter can be a nasty problem too ;)
Not Steve Mcconnell Send private email
Friday, August 10, 2007
 
 
It might be a bit late for a comment on this thread, but I've personally done something like this.

The time I did it, I wanted a "contained" object to "know" what its parent/creator was.  This allowed "upward" traversal as well as "downward".
AllanL5
Saturday, August 18, 2007
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz