From: Daniel Pitts on
So, I know why it is bad for the "this" reference to escape the
constructor, and that many people advocate using a static factory to
help alleviate this problem, but it seems to me that you could run into
the same kind of trouble.

Any time you pass an instance to another class before it is fully
initialized, you run the risk of that other class doing things that it
shouldn't. As far as I know there isn't a way to ensure an atomic
operation that expresses relationships between many objects to many
other objects. Any setSomething method has the right to call any public
method on the Something instance it is passed. It seems like it would
be a burden to add a "completely initialized" runtime check on every
behavior/knowledge querying method. The best it could do is throw an
IllegalStateException. If you have a lot of places this could happen it
become onerous to implement them all.

I suppose you could create some sort of universal contract/convention
that relationship builders (generally constructors and setters) don't do
anything to the objects they receive or already know about, other than
to save the given reference. This seems fragile at best, because the
compiler has no way to enforce this, and someone may unwittingly access
an object before all its required relationships are fully configured.

This is especially troublesome with circular references, which I've been
told should be avoided (probably for just this reason). Unfortunately,
I don't see a rule that can be applied to systematically avoid circular
during initialization. For my particular case.
I have a class Robot, which has a Computer object, which has a Memory
object and a Bus object. The Computer needs to know about the Robot,
and visa versa. I can instantiate them separately, and then pass the
references of each other to each other, but the Computer implementor
would have to explicitly know that they can't access the Robot object
during that reference exchange.

Of course, I could just be confusing matters and making this into a
bigger problem than it is. Any thoughts?
--
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
From: Lasse Reichstein Nielsen on
Daniel Pitts <newsgroup.spamfilter(a)virtualinfinity.net> writes:

> This is especially troublesome with circular references, which I've
> been told should be avoided (probably for just this reason).
> Unfortunately, I don't see a rule that can be applied to
> systematically avoid circular during initialization. For my
> particular case.
> I have a class Robot, which has a Computer object, which has a Memory
> object and a Bus object. The Computer needs to know about the Robot,
> and visa versa.

Why? What is the relationship between Robot and Computer that the
references model? Does that relationship really need to be created at
the time the Robot and/or Computer is created?
Can a computer not be moved to another computer?
Are the Robot and Computer really separate entities, or does a Robot
have a Computer aspect to it ... e.g., by implementing a Computer
interface?

> I can instantiate them separately, and then pass the
> references of each other to each other, but the Computer implementor
> would have to explicitly know that they can't access the Robot object
> during that reference exchange.

"Computer" sounds more generic than something that inherently knows
about a Robot.

> Of course, I could just be confusing matters and making this into a
> bigger problem than it is. Any thoughts?

I have this problem with MVC all the time :)

/L
--
Lasse Reichstein Nielsen - lrn(a)hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'
From: Roedy Green on
On Sun, 28 Oct 2007 13:42:05 -0700, Daniel Pitts
<newsgroup.spamfilter(a)virtualinfinity.net> wrote, quoted or indirectly
quoted someone who said :

>So, I know why it is bad for the "this" reference to escape the
>constructor, and that many people advocate using a static factory to
>help alleviate this problem, but it seems to me that you could run into
>the same kind of trouble.

There is a similar problem of calling virtual methods in constructors
that may access uninitialised (but zeroed) fields.

I think what Java aims to do is prevent you from doing anything that
will crash the JVM. However, you are free to write programs that give
meaningless results.

The idea is they will put in a safety net whereever it is easy to do
so, but feel no guilt about allowing you to write silly code.

--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com
From: Daniel Pitts on
Roedy Green wrote:
> On Sun, 28 Oct 2007 13:42:05 -0700, Daniel Pitts
> <newsgroup.spamfilter(a)virtualinfinity.net> wrote, quoted or indirectly
> quoted someone who said :
>
>> So, I know why it is bad for the "this" reference to escape the
>> constructor, and that many people advocate using a static factory to
>> help alleviate this problem, but it seems to me that you could run into
>> the same kind of trouble.
>
> There is a similar problem of calling virtual methods in constructors
> that may access uninitialised (but zeroed) fields.
>
> I think what Java aims to do is prevent you from doing anything that
> will crash the JVM. However, you are free to write programs that give
> meaningless results.
>
> The idea is they will put in a safety net whereever it is easy to do
> so, but feel no guilt about allowing you to write silly code.
>
Calling possibly overridden methods is the (maybe not obviously) same as
allowing a this reference to escape.

In any case, I'm trying to avoid writing silly code. To me, silly means
code that is too complex and too defensive, or code that is to
simplistic and not "correct".

Thanks,
Daniel
--
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
From: Dmitry A. Kazakov on
On Sun, 28 Oct 2007 13:42:05 -0700, Daniel Pitts wrote:

> So, I know why it is bad for the "this" reference to escape the
> constructor, and that many people advocate using a static factory to
> help alleviate this problem, but it seems to me that you could run into
> the same kind of trouble.
>
> Any time you pass an instance to another class before it is fully
> initialized, you run the risk of that other class doing things that it
> shouldn't. As far as I know there isn't a way to ensure an atomic
> operation that expresses relationships between many objects to many
> other objects.

The problem is not in whether operators are atomic or not. Clearly public
operations have to honor object invariants. The problem is the language
design and improper construction model of. While being constructed the
object does not yet exist, hence a call to *any* its public method is
illegal. As simple as that. When the specific object is constructed you can
call any *specific* method, but it is still illegal to call any
*dispatching* ones, any method potentially dispatching from inside. Only
when the polymorphic object is finally constructed one can dispatch. This
is the semantics of construction of a class instance, which you should
mentally map onto an [admittedly inconsistent] implementation of in the
given programming language (like C++ or Java).

> This is especially troublesome with circular references, which I've been
> told should be avoided (probably for just this reason). Unfortunately,
> I don't see a rule that can be applied to systematically avoid circular
> during initialization.

No such thing can exist. It is as above. A reference may not exist before
the target object. And the target object does not before construction.
Hence, there cannot be any circular references upon initialization. Your
problem is that semantically, you take a raw pointer (to specific object)
and then cast it to a reference to a polymorphic object. That is
semantically illegal, even if the compiler does not tell you so.

> I have a class Robot, which has a Computer object, which has a Memory
> object and a Bus object. The Computer needs to know about the Robot,
> and visa versa.

Then one object should be able to live without another. That would break
the circle. You first create, say, computer without any robot and then
attach a robot to it. Further, a robot should be functional when its
computer has no robot attached.

However, circular dependencies usually indicate a design problem. Perhaps
you should reconsider your design.

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de