Complex object graph and "this" escaping constructor.

Discussion in 'Java' started by Daniel Pitts, Oct 28, 2007.

  1. Daniel Pitts

    Daniel Pitts Guest

    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/>
    Daniel Pitts, Oct 28, 2007
    #1
    1. Advertising

  2. Daniel Pitts <> 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 -
    DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
    'Faith without judgement merely degrades the spirit divine.'
    Lasse Reichstein Nielsen, Oct 29, 2007
    #2
    1. Advertising

  3. Daniel Pitts

    Roedy Green Guest

    On Sun, 28 Oct 2007 13:42:05 -0700, Daniel Pitts
    <> 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
    Roedy Green, Oct 29, 2007
    #3
  4. Daniel Pitts

    Daniel Pitts Guest

    Lasse Reichstein Nielsen wrote:
    > Daniel Pitts <> 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?

    Really, a computer is an aspect of a Robot, but it is complex enough
    that I'd like to separate it out. A robot also has a weapon, heatsink,
    engine, shield, etc... The computer is the one that actuates all of
    these, so needs a reference either to those, or to the computer which
    owns them.

    Of course, I realized after-the-fact that I should probably just use an
    event driven system instead. Eg. the weapon registers itself as a
    listener on the appropriate bus channel of the computer.
    >
    >> 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.

    In this simulation, it is coupled to the robot. However, using the event
    model I can decouple it.
    >
    >> 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 :)

    Yeah, that's the other issue I'm dealing with on the same project ;)

    Thanks.

    --
    Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
    Daniel Pitts, Oct 29, 2007
    #4
  5. Daniel Pitts

    Daniel Pitts Guest

    Roedy Green wrote:
    > On Sun, 28 Oct 2007 13:42:05 -0700, Daniel Pitts
    > <> 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/>
    Daniel Pitts, Oct 29, 2007
    #5
  6. Daniel Pitts <> writes:

    > Lasse Reichstein Nielsen wrote:


    > Really, a computer is an aspect of a Robot, but it is complex enough
    > that I'd like to separate it out. A robot also has a weapon,
    > heatsink, engine, shield, etc... The computer is the one that
    > actuates all of these, so needs a reference either to those, or to the
    > computer which owns them.


    Ah. I still think the computer could exist on its own, and it should
    then accept references to the parts it really needs, and the Robot,
    which is the concept combining the parts, injects references to its
    parts into the computer when it is built.

    Until the computer is placed inside a robot, it won't have any parts
    to control.

    Yes, I'm a fan of dependency injection :)

    Is the robot any more than the sum of its parts?

    > Of course, I realized after-the-fact that I should probably just use
    > an event driven system instead. Eg. the weapon registers itself as a
    > listener on the appropriate bus channel of the computer.


    That's another approach, which allows even greater decoupling.
    The computer doesn't even need to know that there is a recipient for
    its events.

    /L
    --
    Lasse Reichstein Nielsen -
    DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
    'Faith without judgement merely degrades the spirit divine.'
    Lasse Reichstein Nielsen, Oct 29, 2007
    #6
  7. 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
    Dmitry A. Kazakov, Oct 29, 2007
    #7
  8. On 28 Oct, 20:42, 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.


    yes...not sure about the static factory bit...but lets leave it.

    >
    > 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.


    hmmmm

    it is 'logically valid' to consider objects with circular references
    the problem, as you say comes to construction.....I need to create my
    chicken and egg at the same time.....which I clearly can't.

    But the problem in some sense is not an OO one....it's a real world
    one....see below....


    >
    > 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?


    your robot, computer examples is quite nice.....

    but if I were to create a robot and a computer in the real world how
    would I do it? At what point does it become a robot?

    In the real world I would create a mechanical robot chassis.....and
    then add a computer to it....i.e. the construction of a 'robot'
    requires a constructed computer....in the real world the computer does
    not have to be embedded in a robot...so why would you do this in
    software.

    interface IComputer
    {
    ..... bla....
    }


    class Robot : IRobot
    {
    public Robot(IComputer computer)
    {
    ....bla....
    }
    }

    > --
    > Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
    Mark Nicholls, Oct 29, 2007
    #8
  9. Daniel Pitts

    Daniel Pitts Guest

    Lasse Reichstein Nielsen wrote:
    > Daniel Pitts <> writes:
    >
    >> Lasse Reichstein Nielsen wrote:

    >
    >> Really, a computer is an aspect of a Robot, but it is complex enough
    >> that I'd like to separate it out. A robot also has a weapon,
    >> heatsink, engine, shield, etc... The computer is the one that
    >> actuates all of these, so needs a reference either to those, or to the
    >> computer which owns them.

    >
    > Ah. I still think the computer could exist on its own, and it should
    > then accept references to the parts it really needs, and the Robot,
    > which is the concept combining the parts, injects references to its
    > parts into the computer when it is built.
    >
    > Until the computer is placed inside a robot, it won't have any parts
    > to control.
    >
    > Yes, I'm a fan of dependency injection :)

    I'm a fan of DI, but more specifically (or is it generally) a fan of
    inversion of control.
    >
    > Is the robot any more than the sum of its parts?
    >
    >> Of course, I realized after-the-fact that I should probably just use
    >> an event driven system instead. Eg. the weapon registers itself as a
    >> listener on the appropriate bus channel of the computer.

    >
    > That's another approach, which allows even greater decoupling.
    > The computer doesn't even need to know that there is a recipient for
    > its events.

    Right, and its events will be as generic as Memory at Address 6 set to,
    or Port number 16 read.


    Thanks for the reply.

    --
    Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
    Daniel Pitts, Oct 29, 2007
    #9
  10. Daniel Pitts

    H. S. Lahman Guest

    Responding to Pitts...

    > 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 would rephrase the first sentence. It is bad practice to instantiate
    relationships with other objects if the object in hand is not properly
    initialized. Generally we use factory objects to manage instantiation
    for two reasons.

    The first is to encapsulate the business rules and policies of
    instantiation because those rules and policies are likely to be
    different than those governing collaboration within the problem
    solution. A corollary is that the factory object's /only/ business with
    the object is instantiation. So invoking other methods on the object
    should not be an issue and should be easily enforcible with good naming
    conventions and peer reviews.

    A second, related reason is that we can control when the object's
    relationships are instantiated. One practice the factory can enforce is
    that the object is fully initialized prior to instantiating any
    relationships. That way no other object has access to the object until
    it is properly prepared for collaboration.

    A corollary is that a factory method provides a scope that is more
    manageable. Thus when concurrency is an issue one only needs to block
    around the scope of the factory method, which is is usually <relatively>
    easy to do and can be mapped readily into distributed environments. So
    long as the object is instantiated, fully initialized, and all its
    relationships are instantiated within the scope of the factory method,
    referential and data integrity should be a minor issue.

    Conversely, as soon as initialization and/or instantiation of
    unconditional relationships is split among multiple object methods, one
    is in a Pandora's Box situation and the developer must take special
    precautions in the OOA/D to ensure that referential and data integrity
    is not violated. Generally such situations are quite fragile, especially
    during maintenance, so OO reviewers are going to want a lot of
    justification for not encapsulating all the instantiation in a single
    method.

    BTW, I don't see why one needs static factory methods or what using a
    'this' pointer outside constructors has to do with this issue.

    > 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.


    First, I am not sure why the computer hardware is being modeled in a
    game simulation(?)

    But, assuming there is a reason for that, let's ge a bit more specific:

    [Robot]
    | 0..*
    | controls
    |
    | R1
    |
    | 1 1 R2 contains 1
    [Computer] ----------------- [Memory]
    | 1
    | located in
    |
    | R3
    |
    | 1
    [Bus]

    Here the unconditional nature of the R2 and R3 relationships requires
    that all three objects be instantiated and the relationships are in
    place before any collaborations with any of them. One likely approach
    would be to have a single ComputerFactory::create method that
    instantiates all three objects and their relationships within its scope.
    In C++ (I don't do Java) that method might look something like:

    ComputerFactory::create
    {
    Computer* myComputer;
    Memory* myMemory;
    Bus* myBus;

    // get any attribute values needed for initialization

    // instantiate objects
    myComputer = new Computer; // with any attribute values
    myMemory = new Memory; // with any attribute values
    myBus = new Bus; // with any attribute values

    // instantiate relationships
    myComputer->setMemory(myMemory);
    myComputer->setBus(myBus);

    return myComputer;
    }

    If instead the objects are instantiated in separate methods, then you
    need to be very careful that there is no way to collaborate with any of
    them until they all have been instantiated. One way to ensure that would
    be to instantiate R2 and R3 in the last factory method in the sequence.
    [Just make sure nobody changes the sequence during maintenance! That's
    why such instantiation is fragile.]

    Now the R1 relationship conditionality requires that a Computer be
    available when a Robot is instantiated, but doesn't require a Robot to
    be around when a Computer is created. So we could use
    RobotFactory::create to create the Robot instance and instantiate R1.
    But we would have to provide that method with the proper Computer
    reference, which implies that we need to invoke ComputerFactory::create
    before RobotFactory::create.

    Bottom line: the conditionality of the problem space relationships
    usually dictates how the instantiation should be handled.



    *************
    There is nothing wrong with me that could
    not be cured by a capful of Drano.

    H. S. Lahman

    Pathfinder Solutions
    http://www.pathfindermda.com
    blog: http://pathfinderpeople.blogs.com/hslahman
    "Model-Based Translation: The Next Step in Agile Development". Email
    for your copy.
    Pathfinder is hiring:
    http://www.pathfindermda.com/about_us/careers_pos3.php.
    (888)OOA-PATH
    H. S. Lahman, Oct 29, 2007
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. George Sakkis
    Replies:
    1
    Views:
    434
    Szabolcs Nagy
    Jan 29, 2007
  2. Dr Ann Huxtable

    Missing Graph.h and (Graph.lib) woes - any help

    Dr Ann Huxtable, Dec 21, 2004, in forum: C Programming
    Replies:
    6
    Views:
    627
    Dr Ann Huxtable
    Dec 21, 2004
  3. Jef Driesen
    Replies:
    3
    Views:
    2,527
    mlimber
    Jan 24, 2006
  4. Generic Usenet Account
    Replies:
    10
    Views:
    2,197
  5. Emilio Mayorga
    Replies:
    6
    Views:
    314
    Martien Verbruggen
    Oct 8, 2003
Loading...

Share This Page