Constructor

Discussion in 'Java' started by Philipp, Sep 24, 2008.

  1. Philipp

    Philipp Guest

    Hello,
    I have a simple (?) question.

    If I write:
    <code>
    MyClass object = new MyClass(someArgument);
    object.doStuff();
    </code>

    Do I have a guarantee that object is not null when I call doStuff? Or
    is there a possible execution path which reaches .doStuf() with object
    being null?

    Thanks Phil
     
    Philipp, Sep 24, 2008
    #1
    1. Advertising

  2. Philipp

    Bo Vance Guest

    Philipp wrote:
    > Hello,
    > I have a simple (?) question.
    >
    > If I write:
    > <code>
    > MyClass object = new MyClass(someArgument);
    > object.doStuff();
    > </code>
    >
    > Do I have a guarantee that object is not null when I call doStuff? Or
    > is there a possible execution path which reaches .doStuf() with object
    > being null?
    >
    > Thanks Phil

    No such guarantee.
    try {
    MyClass object =
    new MyClass(someArgument);
    object.doStuff();
    } catch (someE e) {
    some handling
    } // guaranteed object.doStuff() won't be called if
    // new MyClass(someArgument) throws.
    See the JLS subsection:
    15.9.4 Run-time Evaluation of Class Instance Creation Expressions
    <http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.9.4>
     
    Bo Vance, Sep 24, 2008
    #2
    1. Advertising

  3. Philipp wrote:
    > Hello,
    > I have a simple (?) question.
    >
    > If I write:
    > <code>
    > MyClass object = new MyClass(someArgument);
    > object.doStuff();
    > </code>
    >
    > Do I have a guarantee that object is not null when I call doStuff? Or
    > is there a possible execution path which reaches .doStuf() with object
    > being null?


    You do have a guarantee, unless you go out of your way to remove it,
    for example with a badly designed try-catch:

    <*bad* code>
    MyClass object = null;
    try {
    object = new MyClass(someArgument);
    } catch (Exception e){
    System.err.println("MyClass constructor failure "+e.getMessage());
    }
    object.doStuff();
    </*bad* code>

    In this version, if the constructor throws an exception, object will be
    null at the object.doStuff() call.

    Patricia
     
    Patricia Shanahan, Sep 24, 2008
    #3
  4. Philipp

    Bo Vance Guest

    bugbear wrote:
    > Bo Vance wrote:
    >> Philipp wrote:
    >>> Hello,
    >>> I have a simple (?) question.
    >>>
    >>> If I write:
    >>> <code>
    >>> MyClass object = new MyClass(someArgument);
    >>> object.doStuff();
    >>> </code>
    >>>
    >>> Do I have a guarantee that object is not null when I call doStuff? Or
    >>> is there a possible execution path which reaches .doStuf() with object
    >>> being null?
    >>>
    >>> Thanks Phil

    >> No such guarantee.
    >> try {
    >> MyClass object =
    >> new MyClass(someArgument);
    >> object.doStuff();
    >> } catch (someE e) {
    >> some handling
    >> } // guaranteed object.doStuff() won't be called if
    >> // new MyClass(someArgument) throws.
    >> See the JLS subsection:
    >> 15.9.4 Run-time Evaluation of Class Instance Creation Expressions
    >> <http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.9.4>

    >
    >
    > The recent thread "To check or not to check for NULL?" disagrees with you.
    >


    Yes, up to the point at which Patricia demonstrates a counter example.
    Granted Phil's snippet didn't include a try/catch block.
    For the record: I stand corrected. 'new' will never evaluate to null.
    Thanks, and my apologies to Phil.
    --
    BV
     
    Bo Vance, Sep 24, 2008
    #4
  5. Philipp

    Bo Vance Guest

    Lew wrote:
    > Philipp wrote:
    >>> If I write:
    >>> <code>
    >>> MyClass object = new MyClass(someArgument);
    >>> object.doStuff();
    >>> </code>
    >>>
    >>> Do I have a guarantee that object is not null when I call doStuff?

    >
    > Yes.
    >
    > 'new' cannot return 'null'.
    >
    >>> Or is there a possible execution path which reaches .doStuf() [sic]
    >>> with object
    >>> being null?

    >
    > Bo Vance wrote:
    >> No such guarantee.
    >> try {
    >> MyClass object =
    >> new MyClass(someArgument);
    >> object.doStuff();
    >> } catch (someE e) {
    >> some handling
    >> } // guaranteed object.doStuff() won't be called if
    >> // new MyClass(someArgument) throws.
    >> See the JLS subsection:
    >> 15.9.4 Run-time Evaluation of Class Instance Creation Expressions
    >> <http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.9.4>

    >
    >
    > This doesn't answer the OP's question. That's how the execution might
    > *not* reach 'doStuff()', but they asked how it might *reach* 'doStuff()'
    > with 'object' not assigned (or assigned 'null').
    >
    > For that read the JLS on "definite assignment". It gets an entire chapter.
    > <http://java.sun.com/docs/books/jls/third_edition/html/defAssign.html>
    >
    > There are ways to reach a reference without it being assigned, basically
    > involving failure to deal with exceptions.
    >
    > Foo foo; // I hate including 'Class' or 'object' in identifiers
    > try
    > {
    > foo = new Foo();
    > }
    > catch ( Exception exc )
    > {
    > // completely fail to handle exc
    > }
    > foo.doStuff(); // error
    >


    Thank you. Hopefully my error has elicited responses that will have
    made the subject clear for the op, Phil.

    --
    BV
     
    Bo Vance, Sep 24, 2008
    #5
  6. bugbear wrote:
    > Patricia Shanahan wrote:
    >> You do have a guarantee, unless you go out of your way to remove it,
    >> for example with a badly designed try-catch:
    >>
    >> <*bad* code>
    >> MyClass object = null;
    >> try {
    >> object = new MyClass(someArgument);
    >> } catch (Exception e){
    >> System.err.println("MyClass constructor failure "+e.getMessage());
    >> }
    >> object.doStuff();
    >> </*bad* code>
    >>
    >> In this version, if the constructor throws an exception, object will be
    >> null at the object.doStuff() call.

    >
    > I will point out that the null value of "object"
    > did NOT come from new.
    >
    > I'm *sure* Patricia knows this.
    >
    > BugBear


    Indeed. More specifically, the JLS guarantees that the result of the
    "new MyClass(someArgument)" is a pointer to a MyClass instance, not
    null. If the variable is null, it must come from somewhere else, such as
    a left over value from before a try-catch block.

    Initializing a final variable is the best guarantee:

    final MyClass object = new MyClass(someArgument);

    Any code using object must be inside any try block containing the
    declaration, so it will not be executed if the constructor throws a
    caught exception or error. Using "final" prevents any subsequent null
    assignment to object.

    Patricia
     
    Patricia Shanahan, Sep 24, 2008
    #6
  7. Patricia Shanahan <> wrote:
    > final MyClass object = new MyClass(someArgument);
    > Any code using object must be inside any try block containing the
    > declaration, so it will not be executed if the constructor throws a
    > caught exception or error. Using "final" prevents any subsequent null
    > assignment to object.


    If I had code like this:
    Foo foo;
    try { foo = new Foo(...); }
    catch (...) { ... }
    finally { ... }
    foo.bar();

    Then wouldn't/shouldn't the compiler reject it anyway with
    words like "use of possibly uninitialized variable" ?

    But then it might mislead some to just add "=null" to the
    declaration, rather than correct the logic in a case like this.
     
    Andreas Leitgeb, Sep 24, 2008
    #7
  8. Philipp wrote:
    > Hello,
    > I have a simple (?) question.
    >
    > If I write:
    > <code>
    > MyClass object = new MyClass(someArgument);
    > object.doStuff();
    > </code>
    >
    > Do I have a guarantee that object is not null when I call doStuff?


    Yes.

    >Or
    > is there a possible execution path which reaches .doStuf() with
    > object
    > being null?


    No.
     
    Mike Schilling, Sep 24, 2008
    #8
  9. Andreas Leitgeb wrote:
    > Patricia Shanahan <> wrote:
    >> final MyClass object = new MyClass(someArgument);
    >> Any code using object must be inside any try block containing the
    >> declaration, so it will not be executed if the constructor throws a
    >> caught exception or error. Using "final" prevents any subsequent
    >> null
    >> assignment to object.

    >
    > If I had code like this:
    > Foo foo;
    > try { foo = new Foo(...); }
    > catch (...) { ... }
    > finally { ... }
    > foo.bar();
    >
    > Then wouldn't/shouldn't the compiler reject it anyway with
    > words like "use of possibly uninitialized variable" ?


    Certainly, assuming (as I'm sure you meant) that neither the catch
    block nor the finally block assigns to foo.
     
    Mike Schilling, Sep 24, 2008
    #9
  10. Philipp

    Roedy Green Guest

    On Wed, 24 Sep 2008 01:48:09 -0700 (PDT), Philipp <>
    wrote, quoted or indirectly quoted someone who said :

    >Do I have a guarantee that object is not null when I call doStuff? Or
    >is there a possible execution path which reaches .doStuf() with object
    >being null?


    It is quite nice. Not only can be you be absolutely sure new returned
    an actual object, you can also be sure the constructor completed
    normally right after the new.

    Otherwise you would have an exception which you may optionally catch.
    Of course you can be perverse and try to access the object in your
    catch or after you have been notified of the problem.

    --
    Roedy Green Canadian Mind Products
    http://mindprod.com/politics/harper.html
    Anyone but Harper for Prime Minister of Canada
     
    Roedy Green, Sep 24, 2008
    #10
  11. Roedy Green wrote:
    > On Wed, 24 Sep 2008 01:48:09 -0700 (PDT), Philipp <>
    > wrote, quoted or indirectly quoted someone who said :
    >
    >> Do I have a guarantee that object is not null when I call doStuff?
    >> Or
    >> is there a possible execution path which reaches .doStuf() with
    >> object being null?

    >
    > It is quite nice. Not only can be you be absolutely sure new
    > returned
    > an actual object, you can also be sure the constructor completed
    > normally right after the new.
    >
    > Otherwise you would have an exception which you may optionally
    > catch.
    > Of course you can be perverse and try to access the object in your
    > catch or after you have been notified of the problem.


    Nitpick: you can't access the object, since there won't be any
    reference to it. You can use the reference that was going to be
    assigned to it, but you'll see its previous contents.
     
    Mike Schilling, Sep 24, 2008
    #11
  12. Philipp

    zerg Guest

    Mike Schilling wrote:
    > Philipp wrote:
    >> Hello,
    >> I have a simple (?) question.
    >>
    >> If I write:
    >> <code>
    >> MyClass object = new MyClass(someArgument);
    >> object.doStuff();
    >> </code>
    >>
    >> Do I have a guarantee that object is not null when I call doStuff?

    >
    > Yes.
    >
    >> Or
    >> is there a possible execution path which reaches .doStuf() with
    >> object
    >> being null?

    >
    > No.


    Interestingly, it IS possible for slightly different code:

    object = new MyClass(someArgument);
    object.doStuff();

    For it to happen here, "object" must not be a local reference, and code
    running in a different thread has to assign it null, and the scheduler
    has to happen to run that bit of code for that other thread in between
    running the two statements above in THEIR thread.

    Obviously, this is avoided if one synchronizes on whatever object holds
    the reference "object" in any threaded code that uses it. (If it's a
    static member of some class Foo, you may synchronize on Foo.class!)

    So besides exception mishandling in between the assignment and the use,
    concurrency can booger things up if the reference is visible in more
    than one thread and is non-final.

    final MyClass object = new MyClass(someArgument);

    is 100% safe from all of these issues, so long as the reference never
    has to be reassigned (and it's not a static member or else the
    constructor can't throw or else if the constructor does throw, it's a
    showstopper for the application anyway).
     
    zerg, Sep 24, 2008
    #12
  13. Philipp

    zerg Guest

    Andrea Francia wrote:
    > public class Main {
    >
    > static Foo escaped;
    >
    > static class Foo {
    > public Foo() {
    > escaped = this; // escaping! don't do this at home!
    > throw new RuntimeException();
    > }
    > }
    >
    > public static void main(String[] args) {
    > try {
    > Foo foo = new Foo();
    > } catch (RuntimeException e) {
    > System.out.println("This reference escaped from constructor:" +
    > escaped);
    > }
    > }
    > }


    I think you'll find that the above code won't compile. Your IDE or javac
    will complain about the use of "this" inside the constructor, other than
    for constructor chaining (e.g. "this(args);").
     
    zerg, Sep 26, 2008
    #13
  14. Philipp

    Tom Anderson Guest

    On Fri, 26 Sep 2008, zerg wrote:

    > Andrea Francia wrote:
    >> public class Main {
    >>
    >> static Foo escaped;
    >>
    >> static class Foo {
    >> public Foo() {
    >> escaped = this; // escaping! don't do this at home!
    >> throw new RuntimeException();
    >> }
    >> }
    >>
    >> public static void main(String[] args) {
    >> try {
    >> Foo foo = new Foo();
    >> } catch (RuntimeException e) {
    >> System.out.println("This reference escaped from constructor:" +
    >> escaped);
    >> }
    >> }
    >> }

    >
    > I think you'll find that the above code won't compile. Your IDE or javac
    > will complain about the use of "this" inside the constructor, other than
    > for constructor chaining (e.g. "this(args);").


    I think you'll find it won't.

    tom

    --
    FRUIT FUCKER has joined the party!
     
    Tom Anderson, Sep 26, 2008
    #14
  15. Tom Anderson wrote:
    > On Fri, 26 Sep 2008, zerg wrote:
    >
    >> Andrea Francia wrote:
    >>> public class Main {
    >>>
    >>> static Foo escaped;
    >>>
    >>> static class Foo {
    >>> public Foo() {
    >>> escaped = this; // escaping! don't do this at home!
    >>> throw new RuntimeException();
    >>> }
    >>> }
    >>>
    >>> public static void main(String[] args) {
    >>> try {
    >>> Foo foo = new Foo();
    >>> } catch (RuntimeException e) {
    >>> System.out.println("This reference escaped from constructor:"
    >>> + escaped);
    >>> }
    >>> }
    >>> }

    >>
    >> I think you'll find that the above code won't compile. Your IDE or
    >> javac will complain about the use of "this" inside the constructor,
    >> other than for constructor chaining (e.g. "this(args);").

    >
    > I think you'll find it won't.


    Tom and Andrea are (unfortunately) correct.

    Note that this kind of escape is a bad idea even if the constructor will
    (eventually) succeeed, since it makes a partially constructed object visible
    to other threads. NetBeans used to use a pattern like this for its
    DataObjects (roughly, objects that represent a file known to the IDE)

    abstract class DataObject
    {
    protected DataObject()
    {
    register(this); // add this to the global list of DataObjects
    }
    }

    The result, that other threads in the IDE would now see partially
    constructed objects, caused intermittent and intractable problems. I don't
    know (and don't at this point really much care) whether this has been fixed.
     
    Mike Schilling, Sep 26, 2008
    #15
  16. Philipp

    zerg Guest

    Tom Anderson wrote:
    >> I think you'll find that the above code won't compile. Your IDE or
    >> javac will complain about the use of "this" inside the constructor,
    >> other than for constructor chaining (e.g. "this(args);").

    >
    > I think you'll find it won't.


    I have *definitely* seen such errors when trying tricks very much like
    this (tricks that I now realize were ill-advised), involving trying to
    export "this" in some manner from a constructor.

    Perhaps some implementations have additional "rules" to try to protect
    users from doing exactly this sort of thing?
     
    zerg, Sep 26, 2008
    #16
  17. Philipp

    zerg Guest

    Mike Schilling wrote:
    >>> I think you'll find that the above code won't compile. Your IDE or
    >>> javac will complain about the use of "this" inside the constructor,
    >>> other than for constructor chaining (e.g. "this(args);").

    >> I think you'll find it won't.

    >
    > Tom and Andrea are (unfortunately) correct.


    I have *definitely* seen such errors when trying tricks very much like
    this (tricks that I now realize were ill-advised), involving trying to
    export "this" in some manner from a constructor.

    Perhaps some implementations have additional "rules" to try to protect
    users from doing exactly this sort of thing?
     
    zerg, Sep 26, 2008
    #17
  18. Philipp

    Mark Space Guest

    Eric l wrote:

    > - Make all the constructors private and use factory methods,
    > with the drawback that the class can't be extended. (This
    > approach avoids the quibble mentioned above, assuming the
    > registration occurs in the factory rather than in the
    > constructor.)


    This is what I would do. Bloch even talks about factory methods in Item
    1 of Effective Java. I think there aren't enough folks using factory
    methods if he puts it as #1. They can be clumsy to work with, and seem
    un-OO, but factory methods are a great pattern and should be used more
    (when appropriate, of course).

    I wonder if providing an abstract class to base future classes on would
    work, if extension is important. Hmm, but it would be possible to use
    the class outside of the factory method. Documentation might work
    here... so might relentlessly testing each object passed in to make sure
    it was registered. A clever design might even eliminate most of the
    overhead by only checking on a few critical methods.

    I guess you could call your base class the "implementation" class, then
    use a restricted wrapper to get the real object to work on.

    public abstract class Implementation {}

    final public class Wrapper {
    Wrapper( Implementation i ) {} // package private
    }

    public class Factory {
    private Factory() {}
    public static Wrapper getNew( Implementation i ) {
    Wrapper w = new Wrapper( i );
    Registry.register( w ); // not shown
    return w;
    }
    }

    So if all your methods require a Wrapper, the compiler does the checking
    for you. This also seems Dependency Injection-y, which might be a good
    thing.
     
    Mark Space, Sep 27, 2008
    #18
  19. Philipp

    Tom Anderson Guest

    On Fri, 26 Sep 2008, zerg wrote:

    > Tom Anderson wrote:
    >>> I think you'll find that the above code won't compile. Your IDE or javac
    >>> will complain about the use of "this" inside the constructor, other than
    >>> for constructor chaining (e.g. "this(args);").

    >>
    >> I think you'll find it won't.

    >
    > I have *definitely* seen such errors when trying tricks very much like this
    > (tricks that I now realize were ill-advised), involving trying to export
    > "this" in some manner from a constructor.
    >
    > Perhaps some implementations have additional "rules" to try to protect
    > users from doing exactly this sort of thing?


    Perhaps you were using a different language?

    Were these alleged errors showstoppers, or warnings? I could certainly
    believe that some IDE would warn on this (i don't think it's too hard to
    catch), but i'd be very surprised indeed if it was a fail-the-compile
    error. Any idea where you saw them?

    tom

    --
    Demolish serious culture!
     
    Tom Anderson, Sep 27, 2008
    #19
  20. Philipp

    Tom Anderson Guest

    On Fri, 26 Sep 2008, Mark Space wrote:

    > Eric l wrote:
    >
    >> - Make all the constructors private and use factory methods,
    >> with the drawback that the class can't be extended. (This
    >> approach avoids the quibble mentioned above, assuming the
    >> registration occurs in the factory rather than in the
    >> constructor.)

    >
    > This is what I would do. Bloch even talks about factory methods in Item 1 of
    > Effective Java. I think there aren't enough folks using factory methods if
    > he puts it as #1. They can be clumsy to work with, and seem un-OO, but
    > factory methods are a great pattern and should be used more (when
    > appropriate, of course).
    >
    > I wonder if providing an abstract class to base future classes on would work,
    > if extension is important. Hmm, but it would be possible to use the class
    > outside of the factory method. Documentation might work here... so might
    > relentlessly testing each object passed in to make sure it was registered. A
    > clever design might even eliminate most of the overhead by only checking on a
    > few critical methods.
    >
    > I guess you could call your base class the "implementation" class, then use a
    > restricted wrapper to get the real object to work on.
    >
    > public abstract class Implementation {}
    >
    > final public class Wrapper {
    > Wrapper( Implementation i ) {} // package private
    > }
    >
    > public class Factory {
    > private Factory() {}
    > public static Wrapper getNew( Implementation i ) {
    > Wrapper w = new Wrapper( i );
    > Registry.register( w ); // not shown
    > return w;
    > }
    > }


    This more or less what i was thinking - convert inheritance to
    composition, and do the registration in the wrapper after the
    implementation is constructed.

    I was thinking of having a regular constructor on the wrapper, and doing
    it there, but a factory method would be just as good.

    Although if you're going to have a factory method, you might as well just
    do the registration there:

    public static Implementation create() {
    Implementation impl = somehowCreateImplementation() ;
    Registry.register(impl) ;
    return impl ;
    }

    Although the context in which you could use this is a little different to
    what you were describing.

    tom

    --
    Demolish serious culture!
     
    Tom Anderson, Sep 27, 2008
    #20
    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. Giulio
    Replies:
    9
    Views:
    1,067
    Patrick Kowalzick
    Jun 25, 2003
  2. Brett Irving
    Replies:
    3
    Views:
    3,351
    John Harrison
    Jun 29, 2003
  3. lallous
    Replies:
    5
    Views:
    8,874
    David Harmon
    Jan 23, 2004
  4. Aire
    Replies:
    3
    Views:
    487
    Mike Wahler
    Jan 25, 2004
  5. Generic Usenet Account
    Replies:
    10
    Views:
    2,345
Loading...

Share This Page