Constructor

P

Philipp

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
 
B

Bo Vance

Philipp said:
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>
 
P

Patricia Shanahan

Philipp said:
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
 
B

Bo Vance

bugbear said:
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.
 
B

Bo Vance

Lew said:
Yes.

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

Bo said:
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.
 
P

Patricia Shanahan

bugbear said:
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
 
A

Andreas Leitgeb

Patricia Shanahan said:
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.
 
M

Mike Schilling

Philipp said:
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.
 
M

Mike Schilling

Andreas said:
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.
 
R

Roedy Green

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

Mike Schilling

Roedy said:
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.
 
Z

zerg

Mike said:

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

zerg

Andrea said:
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);").
 
T

Tom Anderson

Andrea said:
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
 
M

Mike Schilling

Tom said:
Andrea said:
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.
 
Z

zerg

Tom said:
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?
 
Z

zerg

Mike said:
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?
 
M

Mark Space

Eric said:
- 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.
 
T

Tom Anderson

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
 
T

Tom Anderson

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top