calling own methods from constructor

  • Thread starter Andreas Leitgeb
  • Start date
A

Andreas Leitgeb

There is well-known danger in calling own methods from the
constructor, namely that the method called may be overridden
by a subclass, which is really instanciated, but whose specific
constructor has not yet been run.

I do not intend to delve into the details of static, private
or final methods, or final'ity of the class itself (and maybe
others) avoiding these problems, but instead I'm curious, why
Java just doesn't simply forbid the dangerous calls.

Is there any *good* use of having the constructor call a method
that actually *can* be overridden in a subclass? I mean, are
there (non-anti)patterns of explicitly allowing subclasses to
hook into base-class's construction?

--- sscce Test.java begin ---
public class Test {
Test() { foo(); }
void foo() { }
}
--- sscce Test.java end ---

PS: I know that this is not the only spot where Java does let one
shoot in one's feet. But unlike other situations, this one just
seems so easy to detect from static analysis.
 
T

Tom Anderson

Is there any *good* use of having the constructor call a method that
actually *can* be overridden in a subclass? I mean, are there
(non-anti)patterns of explicitly allowing subclasses to hook into
base-class's construction?

public abstract class Library {
private List<Document> documents;

protected Library() {
documents = new ArrayList<Document>();
Collection<String> titles = listDocuments();
for (String title: titles) {
Document doc = loadDocument(title);
// do other preparatory stuff with the document
documents.add(doc);
}
}

protected abstract Collection<String> listDocuments();
protected abstract Document loadDocument(String title);
}

public class FilesystemLibrary extends Library {
// ...
}

public class WebDavLibrary extends Library {
// ...
}

public class JCRLibrary extends Library {
// ...
}

What are the alternatives?

The obvious one is for the subclass constructor to prepare all the objects
and pass them upward; i think that is likely to lead to a lot of
duplication of effort.

The almost as obvious one is to push the abstract methods out into a
separate interface - DocumentStore, say - and have the subclass
constructor pass up an instance of that.

You could also push the repeated logic out into some sort of factory or
helper, and have the subclasses call that, rather than relying on code in
the supeclass, but that is repetitive, and does nothing to establish
invariants in the superclass.

tom
 
L

Lew

import org.apache.log4j.Logger;
import static org.apache.log4j.getLogger;

public class Foo
{
private final Logger logger = getLogger( getClass() );
// ...
}
 
E

Eric Sosman

public abstract class Library {
private List<Document> documents;

protected Library() {
documents = new ArrayList<Document>();
Collection<String> titles = listDocuments();
for (String title: titles) {
Document doc = loadDocument(title);
// do other preparatory stuff with the document
documents.add(doc);
}
}

protected abstract Collection<String> listDocuments();
protected abstract Document loadDocument(String title);
}

public class FilesystemLibrary extends Library {
// ...
}

public class WebDavLibrary extends Library {
// ...
}

public class JCRLibrary extends Library {
// ...
}

What are the alternatives?

Safer ones, I hope. This code presupposes that the subclass
instance can do useful work before its constructor finishes -- to
put it another way, it assumes that the subclass constructor does
absolutely nothing except call the superclass constructor (and even
that much requires some leaps of faith).

How might Java ensure such an assumption? I can't imagine how
it could be done at compile time, when the suite of subclasses may
not even exist to be inspected. At run time, I guess it could be
done with two additional bits per instance: One that says "The
constructor has not yet returned" and another that says "A virtual
method has been called while the constructor is active." Each
virtual method would copy the first bit to the second, and if the
constructor found the second bit set while doing anything other
than a "return," it could throw an exception.
The obvious one is for the subclass constructor to prepare all the
objects and pass them upward; i think that is likely to lead to a lot of
duplication of effort.

The almost as obvious one is to push the abstract methods out into a
separate interface - DocumentStore, say - and have the subclass
constructor pass up an instance of that.

You could also push the repeated logic out into some sort of factory or
helper, and have the subclasses call that, rather than relying on code
in the supeclass, but that is repetitive, and does nothing to establish
invariants in the superclass.

It seems to me the constructor is doing too much of the heavy
lifting. A Library(Collection<Document>) constructor, with the
Documents already loaded or maybe with "load on first use" flags,
seems a more tenable approach. In particular, it allows the
subclass constructors to choose their own sets of exceptions to
throw, instead of requiring that they all extend exceptions thrown
by the superclass' abstract method declarations.
 
O

Owen Jacobson

There is well-known danger in calling own methods from the
constructor, namely that the method called may be overridden
by a subclass, which is really instanciated, but whose specific
constructor has not yet been run.

I do not intend to delve into the details of static, private
or final methods, or final'ity of the class itself (and maybe
others) avoiding these problems, but instead I'm curious, why
Java just doesn't simply forbid the dangerous calls.

It's hard to prove that a constructor never calls a virtual method. Consider:

public class Foo {
public Foo() {
// internalInit is private, therefore final
this.internalInit();
}

public /* virtual */ void virtualMethod() {
System.out.println("Override me! I dare you.");
}

private void internalInit() {
// Whups! 'this' is not always fully initialized.
this.virtualMethod();
}
}

If you forbid internalInit from calling virtual methods because it is,
itself, called from a constructor, you also prevent it from calling
virtual methods when called from a normal method. If you don't prevent
that, but do prevent Foo's constructor from calling any of its own
virtual methods, then you end up with the question "why does Java make
me use a private method when I want to call a virtual method from a
constructor?" instead.

-o
 
A

Andreas Leitgeb

public abstract class Library {
private List<Document> documents;
protected Library() {
documents = new ArrayList<Document>();
Collection<String> titles = listDocuments();
for (String title: titles) {
Document doc = loadDocument(title);
// do other preparatory stuff with the document
documents.add(doc);
}
}
protected abstract Collection<String> listDocuments();
protected abstract Document loadDocument(String title);
}

public class FilesystemLibrary extends Library {
// ...
}
[...]

Sorry, in my eyes, this is one of the anti-patterns.
What are the alternatives?

It's hard to speculate about alternatives for an artificial example.

I'd say, that they exist for any reasonable specification of the problem,
and "back it up"(*) by declaring specifications for which no (or only
mindboggingly contrived) alternatives exist as unreasonable ;-)

(*): In German, we use double-quotes also to indicate tongue-in-cheek
formulations that aren't to be taken entirely literally/serious.
I've recently learned that they are not always thusly understood,
elsewhere. Therefore this explanation. Is there any common markup
for it that would be recognized in the English-speaking world?
 
A

Andreas Leitgeb

Lew said:
import org.apache.log4j.Logger;
import static org.apache.log4j.getLogger;
public class Foo
{
private final Logger logger = getLogger( getClass() );
// ...
}

I thought, I made it clear, that calling static methods was not relevant
to my question. So, kind of thanks for pointing out that I should have
written non-static in the very line of the question, rather than consider
that clear from the other (snipped by you) paragraphs of my post...
 
A

Andreas Leitgeb

Owen Jacobson said:
There is well-known danger in calling own methods from the
constructor, namely that the method called may be overridden
by a subclass, which is really instanciated, but whose specific
constructor has not yet been run.

I do not intend to delve into the details of static, private
or final methods, or final'ity of the class itself (and maybe
others) avoiding these problems, but instead I'm curious, why
Java just doesn't simply forbid the dangerous calls.

It's hard to prove that a constructor never calls a virtual method. Consider:
[ example of c'tor calling a private method "internalInit", which in turn
calls virtual "virtualMethod". ]

Good point. The compiler couldn't (at least not statically) prevent
indirect calling of overridable non-static methods.

But otoh., it refuses to compile this:
String bad = (String) new Integer(42);
while allowing this: (sure bomb at runtime)
String bad = (String) (Object) new Integer(42);

So, not being able to prevent something happening indirectly,
doesn't imply that the direct way would need to be allowed, too.

So, it boils down to the original question of whether there is also
a good use of constructors (directly or indirectly) invoking
overridable virtual methods.

What it "good"? I have no exact definition, but if one of the
Java gurus (Brian Goetz, Joshua Bloch, James Gosling,...) ever
before suggested a pattern that would involve it, then chances
are good, that I'd accept it. Also, if the JSL or one of the big
Java-based projects used it. Tom's example (Library) didn't
convince me so far.
 
A

Arved Sandstrom

On 11-04-07 05:36 AM, Andreas Leitgeb wrote:
[ SNIP ]
(*): In German, we use double-quotes also to indicate tongue-in-cheek
formulations that aren't to be taken entirely literally/serious.
I've recently learned that they are not always thusly understood,
elsewhere. Therefore this explanation. Is there any common markup
for it that would be recognized in the English-speaking world?

It would be quotation marks, usually double quotes, just as in German.
Even Wikipedia (in its entry for Quotation Marks) refers to the use of
quotation not only for actual quotes, but also to denote irony or
unusual usage. Quotes are also used to indicate non-literal or
self-coined meanings, or to emphasize use of the word rather than its
meaning.

Having said that, there are varying levels of literacy in the
English-speaking world. Not everyone will be aware of the other usages
for quotation marks.

AHS
--
That's not the recollection that I recall...All this information is
certainly in the hands of the auditor and we certainly await his report
to indicate what he deems has occurred.
-- Halifax, Nova Scotia mayor Peter Kelly, who is currently deeply in
the shit
 
R

Roedy Green

Is there any *good* use of having the constructor call a method
that actually *can* be overridden in a subclass?

I have accidentally nailed myself by overriding a method used in a
constructor. I have yet to find a legitimate use for it. It is too
bad the compiler does not complain about it.
 
P

Paul Cager

On Apr 7, 9:36 am, Andreas Leitgeb <[email protected]>
wrote:
....
I'd say, that they exist for any reasonable specification of the problem,
and "back it up"(*) by declaring specifications for which no (or only
mindboggingly contrived) alternatives exist as unreasonable ;-)

(*): In German, we use double-quotes also to indicate tongue-in-cheek
formulations that aren't to be taken entirely literally/serious.
I've recently learned that they are not always thusly understood,
elsewhere.  Therefore this explanation. Is there any common markup
for it that would be recognized in the English-speaking world?

I think we use the same convention in British English. I'm not certain
about our "colonial cousins".

The convention also spills over into spoken English, often using non-
verbal hints. There was also a fad at one time for people to raise
their hands to either side of their head and wriggle two fingers to
imitate quotes. I believe it's only used ironically now.
 
T

Tobias Blass

Owen Jacobson said:
There is well-known danger in calling own methods from the
constructor, namely that the method called may be overridden
by a subclass, which is really instanciated, but whose specific
constructor has not yet been run.

I do not intend to delve into the details of static, private
or final methods, or final'ity of the class itself (and maybe
others) avoiding these problems, but instead I'm curious, why
Java just doesn't simply forbid the dangerous calls.

It's hard to prove that a constructor never calls a virtual method. Consider:
[ example of c'tor calling a private method "internalInit", which in turn
calls virtual "virtualMethod". ]

Good point. The compiler couldn't (at least not statically) prevent
indirect calling of overridable non-static methods.

But otoh., it refuses to compile this:
String bad = (String) new Integer(42);
while allowing this: (sure bomb at runtime)
String bad = (String) (Object) new Integer(42);

So, not being able to prevent something happening indirectly,
doesn't imply that the direct way would need to be allowed, too.

So, it boils down to the original question of whether there is also
a good use of constructors (directly or indirectly) invoking
overridable virtual methods.

What it "good"? I have no exact definition, but if one of the
Java gurus (Brian Goetz, Joshua Bloch, James Gosling,...) ever
before suggested a pattern that would involve it, then chances
are good, that I'd accept it. Also, if the JSL or one of the big
Java-based projects used it. Tom's example (Library) didn't
convince me so far.
Why should it complain about your second example? You tell the Compiler
explicitly "Please consider this Integer as Object and this Object as String,
I know types don't match but I know what I'm doing" (I'm programming in C at
the moment where the Compiler doesn't complain about things javac wouldn't
even compile as in your first example, so YMMV)
 
R

Robert Klemme

I thought, I made it clear, that calling static methods was not relevant
to my question.  So, kind of thanks for pointing out that I should have
written non-static in the very line of the question, rather than consider
that clear from the other (snipped by you) paragraphs of my post...

Well, that is clear, but: getClass() isn't a static method. Note that
Lew did not post the usual idiom with log4j and the like which
typically looks something like this:

private static final Logger logger = Logger.getLogger(Foo.class);

As for me, I can't remember having shot myself in the foot with this
feature of Java (i.e. allowing to invoke virtual methods in
constructor). I reckon, language designers figured that allowing it
is more worthwhile than preventing it. As Thomas pointed out you
would have to provide constructor arguments so subclasses can pass on
data they have created. This is tiresome and may even end up being
inefficient namely in the case where the superclass constructor needs
to decide which methods to call (or whether methods to call). You
would end up creating objects which then need to be discarded if the
super class constructor decides that he does not need them =>
inefficient code.

Btw, the check would be expensive for the compiler and I am also not
sure how that byte code might look like because you need to extend the
restrictions to all methods. Consider

class Foo {
private int v;

public Foo() {
v = init(); // allowed, because it's private
}

public void reinitialize() {
v = init();
}

private int init() {
// allowed, but only if init() is not invoked
// from a constructor:
int x = doSomething();
return x * 10 + 2;
}

/** Sub classes may override this.
* @return a number
*/
protected int doSomething() {
return 5;
}
}


Kind regards

robert
 
L

Lew

I thought, I made it clear, that calling static methods was not relevant
to my question. So, kind of thanks for pointing out that I should have
written non-static in the very line of the question, rather than consider
that clear from the other (snipped by you) paragraphs of my post...

I did not realize that 'getClass()' was static.
 
A

Andreas Leitgeb

Arved Sandstrom said:
It would be quotation marks, usually double quotes, just as in German.
Even Wikipedia (in its entry for Quotation Marks) refers to the use of
quotation not only for actual quotes, but also to denote irony or
unusual usage. Quotes are also used to indicate non-literal or
self-coined meanings, or to emphasize use of the word rather than its
meaning.

Thanks for the info!
Having said that, there are varying levels of literacy in the
English-speaking world. Not everyone will be aware of the other
usages for quotation marks.

:/
 
A

Andreas Leitgeb

Roedy Green said:
I have accidentally nailed myself by overriding a method used in a
constructor. I have yet to find a legitimate use for it. It is too
bad the compiler does not complain about it.

I haven't (yet) been bitten by it, myself.
I just recently came to think about it.
 
A

Andreas Leitgeb

Paul Cager said:
I think we use the same convention in British English. I'm not certain
about our "colonial cousins". :)

The convention also spills over into spoken English, often using non-
verbal hints. There was also a fad at one time for people to raise
their hands to either side of their head and wriggle two fingers to
imitate quotes. I believe it's only used ironically now.

Is that a consequence of the "Austin Powers" movies, or did the
movies only make fun of an already common behavioural pattern?
 
A

Andreas Leitgeb

Tobias Blass said:
It's hard to prove that a constructor never calls a virtual method. Consider:
[ example of c'tor calling a private method "internalInit", which in turn
calls virtual "virtualMethod". ]
Good point. The compiler couldn't (at least not statically) prevent
indirect calling of overridable non-static methods.

But otoh., it refuses to compile this:
String bad = (String) new Integer(42);
while allowing this: (sure bomb at runtime)
String bad = (String) (Object) new Integer(42);
Why should it complain about your second example? You tell the Compiler
explicitly "Please consider this Integer as Object and this Object as String,

It wasn't my intention to criticize that double-casts are allowed,
nor that single casts of incompatible types aren't. Just, that there
already is an example of something bad, that is indirectly possible
but directly forbidden.
I know types don't match but I know what I'm doing"

Interestingly, those cases where such a double cast would
solve a real problem (namely casting between two interfaces
or between a non-final class and an interface & vice versa)
do already work with a single cast, so I don't really understand,
what double casts are really good for.
(I'm programming in C at the moment where the Compiler doesn't
complain about things javac wouldn't even compile as in your
first example, so YMMV)

Casting in C++ is something different than in Java.
Although, if you really do C, not C++, then it's it's
much more like Java, except for the lacking safety net.

I'm doing C++, and recently I noticed a mistake of mine on
rereading it: I had tried to use polymorphism with objects
stored directly in an stl vector<baseclass>... ;-)
Changed it to vector<const baseclass*>, a few "."s to "->"s, and
added a few "new"s, allowing me to continue using polymorphism.
(The vector isn't meant to ever shrink till end of process, so no
extra "delete"s. Also, it only grows during initialization.)
 
A

Andreas Leitgeb

Lew said:
I did not realize that 'getClass()' was static.

I did not realize that getClass() was overidable - a property I even
explicitly repeated in my question. For this, I assumed you were
talking of getLogger().
 
A

Andreas Leitgeb

Robert Klemme said:
Well, that is clear, but: getClass() isn't a static method.

Because getClass() is final, it didn't occur to me, that he
would have put up *that* as an example...
As for me, I can't remember having shot myself in the foot with this
feature of Java (i.e. allowing to invoke virtual methods in
constructor). I reckon, language designers figured that allowing it
is more worthwhile than preventing it. As Thomas pointed out you
would have to provide constructor arguments so subclasses can pass on
data they have created. This is tiresome and may even end up being
inefficient namely in the case where the superclass constructor needs
to decide which methods to call (or whether methods to call). You
would end up creating objects which then need to be discarded if the
super class constructor decides that he does not need them =>
inefficient code.

The example of that Library class-hierarchy looked a bit
contrived to me.
Btw, the check would be expensive for the compiler and I am also not
sure how that byte code might look like because you need to extend the
restrictions to all methods. [...]

It would be already an improvement, if direct calls to such
methods from the constructor were forbidden.
 

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