Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Statements before super()

496 views
Skip to first unread message

Steven Simpson

unread,
Feb 9, 2010, 11:22:35 AM2/9/10
to
Eric Sosman wrote:
> On 2/9/2010 4:49 AM, Pitch wrote:
>> Also, you cannot place any code before super(...) which I already new,
>> and it also sucks. :)
> [...]
>> Anyone knows why is that so?
> [...] If it were possible to
> run arbitrary code on a Sub instance before its Super-ness had
> been established and its Super invariants put in place, you'd
> be working with a Sub that was a Super in name only, but not in
> actuality.

Could that restriction not be loosened in a compiler-verifiable way,
i.e. check that no statement prior to super() uses 'this' (explicitly or
implicitly)? Therefore, there would be no arbitrary code acting on the
Sub instance, until after super().

--
ss at comp dot lancs dot ac dot uk

Lew

unread,
Feb 9, 2010, 11:35:16 AM2/9/10
to
Pitch wrote:
>>> Also, you cannot place any code before super(...) which I already new,
>>> and it also sucks. :)
>> [...]
>>> Anyone knows why is that so?

Eric Sosman wrote:
>> [...] If it were possible to
>> run arbitrary code on a Sub instance before its Super-ness had
>> been established and its Super invariants put in place, you'd
>> be working with a Sub that was a Super in name only, but not in
>> actuality.

Steven Simpson wrote:
> Could that restriction not be loosened in a compiler-verifiable way,
> i.e. check that no statement prior to super() uses 'this' (explicitly or
> implicitly)? Therefore, there would be no arbitrary code acting on the
> Sub instance, until after super().

Anything is possible, but it isn't going to happen.

In the thread you abandoned to post this, Steven, there was a code example of
why it isn't necessary.

--
Lew

Mike Schilling

unread,
Feb 9, 2010, 11:36:04 AM2/9/10
to

You can accomplish this in a roundabout way by calling a static method in
the arguments to "super()"


Lew

unread,
Feb 9, 2010, 11:39:56 AM2/9/10
to
Eric Sosman wrote:
>>> [...] If it were possible to
>>> run arbitrary code on a Sub instance before its Super-ness had
>>> been established and its Super invariants put in place, you'd
>>> be working with a Sub that was a Super in name only, but not in
>>> actuality.

Steven Simpson wrote:
>> Could that restriction not be loosened in a compiler-verifiable way,
>> i.e. check that no statement prior to super() uses 'this' (explicitly
>> or implicitly)? Therefore, there would be no arbitrary code acting
>> on the Sub instance, until after super().

Mike Schilling wrote:
> You can accomplish this in a roundabout way by calling a static method in
> the arguments to "super()"

The method doesn't have to be static. The advantage of a static method is
that the compiler will complain if you refer to instance members, thus
preventing you from relying on incompletely-constructed elements.

--
Lew

Volker Borchert

unread,
Feb 9, 2010, 12:23:04 PM2/9/10
to
Mike Schilling wrote:
> You can accomplish this in a roundabout way by calling a static method in
> the arguments to "super()"

Maybe so, but the most interesting thing to "do" before super() would
be try{ ..., to catch, possibly log, wrap and rethrow exceptions thrown
by the super ctor

--

"I'm a doctor, not a mechanic." Dr Leonard McCoy <mc...@ncc1701.starfleet.fed>
"I'm a mechanic, not a doctor." Volker Borchert <v_bor...@despammed.com>

Markus Eberle

unread,
Feb 9, 2010, 12:49:40 PM2/9/10
to
Am 09.02.2010 18:23, schrieb Volker Borchert:
> Mike Schilling wrote:
>> You can accomplish this in a roundabout way by calling a static method in
>> the arguments to "super()"
>
> Maybe so, but the most interesting thing to "do" before super() would
> be try{ ..., to catch, possibly log, wrap and rethrow exceptions thrown
> by the super ctor

Catching an exception of the super constructor seems to be unwise, as
the object is then in an undefined state.

Cheers,
Markus


Patricia Shanahan

unread,
Feb 9, 2010, 1:12:29 PM2/9/10
to

That is why one should "possibly log, wrap and rethrow" the exception,
not ignore it.

There are several inconveniences associated with constructors, including
this one, that can be avoided by using private constructors that are
only called from static factory methods.

Patricia

markspace

unread,
Feb 9, 2010, 1:15:15 PM2/9/10
to


I'm sure logging an exception and then throwing another exception (or
rethrowing the original) would be fine.

I agree that anything else--logging and ignoring, or logging and
returning immediately without throwing--would be inviting disaster.

Eric Sosman

unread,
Feb 9, 2010, 1:48:31 PM2/9/10
to

Are you sure the method can be non-static? Maybe you're
doing something tricky that I haven't thought of, but when I
try the obvious thing

class Super {
Super(int value) {
System.out.println(value + " is super!");
}
}

class Sub extends Super {
Sub() {
super(makeValue());
}
private /* static */ int makeValue() {
return 42;
}
}

... the compiler complains "cannot reference this before supertype
constructor has been called" at the point of the method call.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Mike Schilling

unread,
Feb 9, 2010, 1:53:33 PM2/9/10
to
Lew wrote:
> Eric Sosman wrote:
>>>> [...] If it were possible to
>>>> run arbitrary code on a Sub instance before its Super-ness had
>>>> been established and its Super invariants put in place, you'd
>>>> be working with a Sub that was a Super in name only, but not in
>>>> actuality.
>
> Steven Simpson wrote:
>>> Could that restriction not be loosened in a compiler-verifiable way,
>>> i.e. check that no statement prior to super() uses 'this'
>>> (explicitly or implicitly)? Therefore, there would be no arbitrary
>>> code acting on the Sub instance, until after super().
>
> Mike Schilling wrote:
>> You can accomplish this in a roundabout way by calling a static
>> method in the arguments to "super()"
>
> The method doesn't have to be static.

It does:

import java.io.*;

class Test extends FilterInputStream
{
Test() throws Exception
{
super(getStream());
}

InputStream getStream() throws Exception
{
return new FileInputStream("foo.txt");
}
}

% javac -g Test.java
Test.java:7: cannot reference this before supertype constructor has been
called
super(getStream());
^
1 error


Lew

unread,
Feb 9, 2010, 1:59:33 PM2/9/10
to
Lew wrote:
>> The method doesn't have to be static. The advantage of a static method
>> is that the compiler will complain if you refer to instance members,
>> thus preventing you from relying on incompletely-constructed elements.

Eric Sosman wrote:
> Are you sure the method can be non-static?

> ... the compiler complains "cannot reference this before supertype
> constructor has been called" at the point of the method call.

(Mike Schilling pointed this out as well.)

I'm wrong.

--
Lew

Steven Simpson

unread,
Feb 9, 2010, 3:44:56 PM2/9/10
to
> the arguments to "super()".
>

I know - I snipped the example from the message I quoted. Didn't think
it was relevant, as I'm just curious as to any technical reason for the
restriction.

As it happens, it might have been relevant, as any expressions appearing
as arguments of super() effectively are prior to it, and the compiler
(as I recall) has to check them for reference to 'this' anyway.

Lothar Kimmeringer

unread,
Feb 9, 2010, 4:05:35 PM2/9/10
to
Patricia Shanahan wrote:

> Markus Eberle wrote:
>>
>> Catching an exception of the super constructor seems to be unwise, as
>> the object is then in an undefined state.
>
> That is why one should "possibly log, wrap and rethrow" the exception,
> not ignore it.

There are so many ways this might end up in a catastrophe
that it's easier to expect the logging to happen in the
class calling the constructor catching the exception.


Regards, Lothar
--
Lothar Kimmeringer E-Mail: spam...@kimmeringer.de
PGP-encrypted mails preferred (Key-ID: 0x8BC3CD81)

Always remember: The answer is forty-two, there can only be wrong
questions!

Lew

unread,
Feb 9, 2010, 4:58:05 PM2/9/10
to
Mike Schilling wrote:
>> You can accomplish this in a roundabout way by calling a static method in
>> the arguments to "super()".

Steven Simpson wrote:
> I know - I snipped the example from the message I quoted. Didn't think
> it was relevant, as I'm just curious as to any technical reason for the
> restriction.

The technical reasons are laid out in the other thread on this topic,
appearing under subject 'object relational database versus "inteligent"
serialization'.

I think of it as the system requiring that there be an object before you can
act on it.

> As it happens, it might have been relevant, as any expressions appearing
> as arguments of super() effectively are prior to it, and the compiler
> (as I recall) has to check them for reference to 'this' anyway.

Thus the requirement that methods or other arguments in the constructor not be
instance-level.

--
Lew

Roedy Green

unread,
Feb 9, 2010, 7:43:10 PM2/9/10
to
On Tue, 09 Feb 2010 16:22:35 +0000, Steven Simpson <s...@domain.invalid>
wrote, quoted or indirectly quoted someone who said :

>Could that restriction not be loosened in a compiler-verifiable way,
>i.e. check that no statement prior to super() uses 'this' (explicitly or
>implicitly)?

It would have to chase any method calls recursively. They might
dynamically load code. I don't think you can tell in general.

Perhaps you could allow an expression involving only literals, static
finals and parameters.

The restriction is onerous. Often I want to transform the constructor
parameters to pass to the super constructor.

Oddly you are allowed method calls in the superconstructor, which
could do bloody well anything.
--
Roedy Green Canadian Mind Products
http://mindprod.com

Every compilable program in a sense works. The problem is with your unrealistic expections on what it will do.

Alessio Stalla

unread,
Feb 10, 2010, 3:33:25 AM2/10/10
to
On Feb 10, 1:43 am, Roedy Green <see_webs...@mindprod.com.invalid>
wrote:

> On Tue, 09 Feb 2010 16:22:35 +0000, Steven Simpson <s...@domain.invalid>
> wrote, quoted or indirectly quoted someone who said :
>
> >Could that restriction not be loosened in a compiler-verifiable way,
> >i.e. check that no statement prior to super() uses 'this' (explicitly or
> >implicitly)?
>
> It would have to chase any  method calls recursively. They might
> dynamically load code.  I don't think you can tell in general.

I think you can. You don't have to chase anything: if you encounter
this.foo() or super.foo() or bar(this), the code is illegal, else it's
not. There's no other way for method calls to access the 'this'
reference. Of course besides method calls you have to guard against
other expressions involving this, like baz = this, quux == this and so
on, but those are easy.

> Perhaps you could allow an expression involving only literals, static
> finals and parameters.

That would be sensible.

> The restriction is onerous.  Often I want to transform the constructor
> parameters to pass to the super constructor.

I often do, too. Also try-catch-rethrow is quite a common need.

> Oddly you are allowed method calls in the superconstructor, which
> could do bloody well anything.

You're right, I never thought about that! Methods can be overridden in
the subclass and access fields that have not yet been initialized, if
they are called from the super constructor. One more sign that
disallowing statements before super() does not guarantee any
additional safety.

Alessio

Pitch

unread,
Feb 10, 2010, 10:45:44 AM2/10/10
to
In article <b366f0eb-11ae-48bb-86b1-67eff9b81a88
@k41g2000yqm.googlegroups.com>, alessi...@gmail.com says...

> > Oddly you are allowed method calls in the superconstructor, which
> > could do bloody well anything.
>
> You're right, I never thought about that! Methods can be overridden in
> the subclass and access fields that have not yet been initialized, if
> they are called from the super constructor. One more sign that
> disallowing statements before super() does not guarantee any
> additional safety.


yep.

--
stirr your cofee properly

Tom Anderson

unread,
Feb 10, 2010, 2:09:42 PM2/10/10
to
On Tue, 9 Feb 2010, Lew wrote:

> Pitch wrote:
>>>> Also, you cannot place any code before super(...) which I already new,
>>>> and it also sucks. :)
>>> [...]
>>>> Anyone knows why is that so?
>
> Eric Sosman wrote:
>>> [...] If it were possible to
>>> run arbitrary code on a Sub instance before its Super-ness had
>>> been established and its Super invariants put in place, you'd
>>> be working with a Sub that was a Super in name only, but not in
>>> actuality.
>
> Steven Simpson wrote:
>> Could that restriction not be loosened in a compiler-verifiable way,
>> i.e. check that no statement prior to super() uses 'this' (explicitly or
>> implicitly)? Therefore, there would be no arbitrary code acting on the
>> Sub instance, until after super().
>
> Anything is possible, but it isn't going to happen.

Which is a shame.

> In the thread you abandoned to post this, Steven, there was a code
> example of why it isn't necessary.

No, there was an example constructed to show that it wasn't necessary, but
which actually showed that it wasn't necessary in one particular case.

Try:

/** An ordered pair of strings. */
class StringPair {
public StringPair(String first, String second) {...}
}

/** Particular kind of string pair which is formed by splitting a string
at the first instance of a given separator character. For example:

new SeparatedString("foo=bar", '=')

is equivalent to:

new StringPair("foo", "bar)
*/
class SeparatedString {
public SeparatedString(String str, char separator) {
// now what?
}
}

Unless you want the split the string twice, your only option is recourse
to a static factory method.

Allowing expressions that didn't touch 'this' before the super call would
have been easy, safe, and much more useful. In terms of safety, it's no
different to allowing expressions as the parameters to super calls, but
much more useful.

tom

--
Hit to death in the future head

Mike Schilling

unread,
Feb 10, 2010, 2:42:29 PM2/10/10
to
Tom Anderson wrote:
> new SeparatedString("foo=bar", '=')
>
> is equivalent to:
>
> new StringPair("foo", "bar)
> */
> class SeparatedString {
> public SeparatedString(String str, char separator) {
> // now what?

this(split(str, separator));
}
}
private String[] split(String str, char separator)
{
...
}

private SeparatedString(String[] strings)
{
super(strings[0], strings[1]);
}

I refuse to be concerned about the cost of the allocation of the String
array.

Propoal:
What would, I think, solve this kind of problem neatly would be to let a
constructor delegate object construction to a static factory method, hiding
the use of the factory from the caller. Something like (I don't like the
"return" syntax much either)

public SeparatedString(String str, char separator) {

return createSeparatedString(String str, char separator);
}

private static SeparatedString createSeparatedString(String str, char
separator) {
...
}

Of course, you'd want Java to guarantee that

1. the returned value isn't null (easy)
2. the returned value is newly created (very difficult, unless we insist
that
A. the factory method be in the same source file, and
B. the assignment "retval = new XXX();" be in the body of that
method)

Oh, and for inner classes, the enclosing value would need to be passed
explicitly to the factory. OK, ignore where I said "neatly".


Tom Anderson

unread,
Feb 10, 2010, 4:57:15 PM2/10/10
to
On Wed, 10 Feb 2010, Mike Schilling wrote:

> Tom Anderson wrote:
>> new SeparatedString("foo=bar", '=')
>>
>> is equivalent to:
>>
>> new StringPair("foo", "bar)
>> */
>> class SeparatedString {
>> public SeparatedString(String str, char separator) {
>> // now what?
>
> this(split(str, separator));
> }
> }
> private String[] split(String str, char separator)
> {
> ...
> }
>
> private SeparatedString(String[] strings)
> {
> super(strings[0], strings[1]);
> }
>
> I refuse to be concerned about the cost of the allocation of the String
> array.

Okay. So now:

/** A string pair combining a search term, and the string resulting from
using the term as the parameter to the supplied query.
*/
class TermAndResult extends StringPair {
public KeyAndValueString(String term, PreparedStatement query) {
// and no, it's not Derby or H2
}
}

Believe me, i can keep contriving examples all week!

> Propoal:
> What would, I think, solve this kind of problem neatly would be to let a
> constructor delegate object construction to a static factory method, hiding
> the use of the factory from the caller.

What would solve the problem is allowing statements before the super call
that don't involve 'this'. This is simple, backwards compatible, and would
be *perfectly safe*!

On compatibility - it's obviously (i think) true that any code valid now
would be valid when the rules were relaxed. Could you change the language
rules without changing the VM spec? The only bit i could find in the VM
spec which bears on what a constructor can do is in 4.8.2 Structural
Constraints:

* When any instance method is invoked or when any instance variable is
accessed, the class instance that contains the instance method or
instance variable must already be initialized.

* There must never be an uninitialized class instance on the operand
stack or in a local variable when any backwards branch is taken. There
must never be an uninitialized class instance in a local variable in code
protected by an exception handler. However, an uninitialized class
instance may be on the operand stack in code protected by an exception
handler. When an exception is thrown, the contents of the operand stack
are discarded.

* Each instance initialization method (3.9), except for the instance
initialization method derived from the constructor of class Object, must
call either another instance initialization method of this or an instance
initialization method of its direct superclass super before its instance
members are accessed. However, instance fields of this that are declared
in the current class may be assigned before calling any instance
initialization method.

The most painful thing there is the ban on backward branches; that rules
out loops before the super invocation. The ban on exception handlers could
also be awkward. I don't understand the rationale behind those particular
rules, so i can't really suggest how they could be relaxed.

tom

--
william gibson said that the future has already happened, it just isn't
evenly distributed. he was talking specifically about finsbury park. --
andy

Mike Schilling

unread,
Feb 10, 2010, 5:00:06 PM2/10/10
to

The same thing, but make "split" talk to the DBMS, and probably thow some
interesting exceptions.


Lew

unread,
Feb 10, 2010, 5:26:19 PM2/10/10
to

Believe us, all those examples you contrive can be handled with existing Java
semantics. Since by definition what you put in there cannot rely on the
instance being constructed, it must be available through a static method call.

Or if not, you can make a factory to create the instance with whatever you
need. A typical pattern is to use a builder in the factory method that starts
with a no-arg constructor, probably 'private', and the setting of necessary
properties to create a viable state.

None of this is about what Java cannot do, since it can, but about how you
wish it would do it, which is tough noogies for you.

--
Lew

Mike Schilling

unread,
Feb 10, 2010, 5:54:59 PM2/10/10
to
Lew wrote:

>
> Believe us, all those examples you contrive can be handled with
> existing Java semantics. Since by definition what you put in there
> cannot rely on the instance being constructed, it must be available
> through a static method call.
> Or if not, you can make a factory to create the instance with
> whatever you need. A typical pattern is to use a builder in the
> factory method that starts with a no-arg constructor, probably
> 'private', and the setting of necessary properties to create a viable
> state.
> None of this is about what Java cannot do, since it can, but about
> how you wish it would do it, which is tough noogies for you.

The part of it I would find annoying (if I thought it existed) would be if
some sorts of initialization could only be done via a factory. A large part
of designing a class is determining what interface it shows to client code.
If the result includes a constructor rather than a factory, changes to the
class's implementation shouldn't force a reversal of that decision.


rossum

unread,
Feb 10, 2010, 5:58:10 PM2/10/10
to
On Tue, 09 Feb 2010 16:22:35 +0000, Steven Simpson <s...@domain.invalid>
wrote:

Static initialisation code in the derived class is run before super()
in the constructor.

rossum


public class Main {

public static void main(String[] args) {

Derived dd = new Derived();

System.out.println("Done.");
} // end main()

} // end class Main


class Base {

public Base() {
System.out.println("Base constructor.");
}

} // end class Base


class Derived extends Base {

static { System.out.println("Derived static code."); }

{ System.out.println("Derived initialisation code."); }

public Derived() {
super();
System.out.println("Derived constructor.");
}
} // end class Derived

**** Output ****

run:
Derived static code.
Base constructor.
Derived code.
Derived constructor.
Done.

Tom Anderson

unread,
Feb 10, 2010, 6:07:07 PM2/10/10
to

Ugh, you're right. Sorry, not thinking terribly clearly there.

> Believe us, all those examples you contrive can be handled with existing
> Java semantics. Since by definition what you put in there cannot rely
> on the instance being constructed, it must be available through a static
> method call.

I'm not claming it can't be done. My point is that this pointless rule
forces ugly and in some cases actually inefficient workarounds. The
problem is the rule. The solution is to change it.

tom

--
Big Bang. No god. Fadeout. End. -- Stephen Baxter

Lew

unread,
Feb 10, 2010, 6:46:05 PM2/10/10
to
rossum wrote:
> Static initialisation code in the derived class is run before super()
> in the constructor.
>
> public class Main {
>
> public static void main(String[] args) {
>
> Derived dd = new Derived();
>
> System.out.println("Done.");
> } // end main()
>
> } // end class Main
>
>
> class Base {
>
> public Base() {
> System.out.println("Base constructor.");
> }
>
> } // end class Base
>
>
> class Derived extends Base {
>
> static { System.out.println("Derived static code."); }
>
> { System.out.println("Derived initialisation code."); }
>
> public Derived() {
> super();
> System.out.println("Derived constructor.");
> }
> } // end class Derived
>
> **** Output ****
>
> run:
> Derived static code.
> Base constructor.
> Derived code.

Since I don't see that string in your example, I'm guessing you meant to put
Derived initialisation code.

The 'println()' call for which is actually part of the constructor, btw.

> Derived constructor.
> Done.

I don't see "Done." in your example code either.

--
Lew

Mike Schilling

unread,
Feb 10, 2010, 7:16:00 PM2/10/10
to
Suppose the call to "super()" needn't be the first line of a constructor.
Discuss the effect and/or legality of the following code:

class MyClass extends YourClass
{
public MyClass(int i)
{
if ( i > 0)
{
super(i);
}
}
...


rossum

unread,
Feb 10, 2010, 7:59:29 PM2/10/10
to

Whoops. I changed the code and then forgot to re-run it. Thanks for
the catch. I c&p'd the previous run.

>
>The 'println()' call for which is actually part of the constructor, btw.
>
>> Derived constructor.
>> Done.
>
>I don't see "Done." in your example code either.

Look in main().

rossum

Eric Sosman

unread,
Feb 10, 2010, 9:29:25 PM2/10/10
to

Illegal[*]: It is possible to construct a MyClass instance
that has not constructed its YourClass aspect.

[*] Well, we're already in fairy-land. But if we're to retain
any sanity, even fairy-land must abide by sane rules.

A fairy-land compiler could detect the failure to call super()
(or the possibility of calling it more than once) with logic similar
to that which real compilers use to detect the use of "possibly
uninitialized" variables. As with the latter, some situations like

class OurClass extends YourClass {
MyClass(String thing) {
switch (thing.length() % 2) {
case 0: super(42); break;
case 1: super(-3); break;
}
}
}

... would be falsely diagnosed as "might not call super()."
(Because javac knows that String's length() method returns an
int, but does not know that the int is non-negative.)

--
Eric Sosman
eso...@ieee-dot-org.invalid

Lew

unread,
Feb 10, 2010, 9:34:14 PM2/10/10
to
Lew wrote:
>> I don't see "Done." in your example code either.

rossum wrote:
> Look in main().

(smacks self in forehead)

Ok.

--
Lew

Mike Schilling

unread,
Feb 11, 2010, 2:34:07 AM2/11/10
to
Eric Sosman wrote:
> On 2/10/2010 7:16 PM, Mike Schilling wrote:
>> Suppose the call to "super()" needn't be the first line of a
>> constructor. Discuss the effect and/or legality of the following
>> code: class MyClass extends YourClass
>> {
>> public MyClass(int i)
>> {
>> if ( i> 0)
>> {
>> super(i);
>> }
>> }
>> ...
>
> Illegal[*]: It is possible to construct a MyClass instance
> that has not constructed its YourClass aspect.
>
> [*] Well, we're already in fairy-land. But if we're to retain
> any sanity, even fairy-land must abide by sane rules.
>
> A fairy-land compiler could detect the failure to call super()
> (or the possibility of calling it more than once) with logic similar
> to that which real compilers use to detect the use of "possibly
> uninitialized" variables.

Now that you mention it, it's almost exactly the same logic used to
determine that final fields are initialized exactly once. The only
difference is that it would also need to detect that instance fields and
methods are accessed only after that's done.


Pitch

unread,
Feb 11, 2010, 7:07:33 AM2/11/10
to
In article <hl0bth$4ll$1...@news.eternal-september.org>,
mscotts...@hotmail.com says...

Actually, read-only (final) fields are maybe the only reason they kept
this rule, so they wouldn't have to check how many if the field was
accessed more than once.

It's a neat little rule that made lazy java designes happy.

Pitch

unread,
Feb 11, 2010, 7:09:13 AM2/11/10
to
In article <hkvi82$usn$1...@news.eternal-september.org>,
mscotts...@hotmail.com says...

If you look at super() as just another method call it's perfectly ok.

Apart from the final fields which would need specific mechanism (a flag
saying it is already initialized).

Patricia Shanahan

unread,
Feb 11, 2010, 10:37:58 AM2/11/10
to

The most complete way of dealing with this would be to have two
concepts, "definitely constructed" and "definitely not constructed" that
would be calculated in a similar way to "definitely assigned".

At the start of the body of the constructor "definitely constructed" is
false and "definitely not constructed" is true.

Use of super and this to call another constructor is permitted if, and
only if, "definitely not constructed" is true.

References that use "this", return and fall through to the end of the
constructor are permitted if, and only if, "definitely constructed" is true.

Even if neither is true, completion through throw of an exception is
permitted.

In the example case, at the end of the if statement "definitely
constructed" is false because of the i >= 0 case. "definitely not
constructed is false because of the i < 0 case. There can be no more
super or this calls, and the constructor must complete by throwing an
exception.

Constructors that follow the current standard would transition to
"definitely constructed" true and "definitely not constructed" false
after the first statement of the constructor body.

Patricia

Lew

unread,
Feb 11, 2010, 11:20:22 AM2/11/10
to
mscotts...@hotmail.com says...
>> Suppose the call to "super()" needn't be the first line of a constructor.
>> Discuss the effect and/or legality of the following code:
>>
>> class MyClass extends YourClass
>> {
>> public MyClass(int i)
>> {
>> if ( i > 0)
>> {
>> super(i);
>> }
>> }
>> ...

Pitch wrote:
> If you look at super() as just another method call it's perfectly ok.

Constructor calls are not method calls. So that won't work.

--
Lew

Mike Schilling

unread,
Feb 11, 2010, 11:30:03 AM2/11/10
to
Pitch wrote:
> In article <hkvi82$usn$1...@news.eternal-september.org>,
> mscotts...@hotmail.com says...
>>
>> Suppose the call to "super()" needn't be the first line of a
>> constructor. Discuss the effect and/or legality of the following
>> code:
>>
>> class MyClass extends YourClass
>> {
>> public MyClass(int i)
>> {
>> if ( i > 0)
>> {
>> super(i);
>> }
>> }
>> ...
>
> If you look at super() as just another method call it's perfectly ok.

But it isn't "just another method call", which is the point of the example.
It's the call that guarantees that the superclass, starting from a
completely uninitialized state, has been fully initialized. It needs to be
called precisely once, and that needs to be done before any instance methods
are called or instance fields accessed.


Mike Schilling

unread,
Feb 11, 2010, 11:33:01 AM2/11/10
to

Good Lord, Patricia, I said "discuss", not "develop the complete theory of"
:-)


Eric Sosman

unread,
Feb 11, 2010, 1:57:43 PM2/11/10
to
On 2/11/2010 11:33 AM, Mike Schilling wrote:
> Patricia Shanahan wrote:
>> [... sensible stuff ...]

> Good Lord, Patricia, I said "discuss", not "develop the complete theory of"
> :-)

She's a PhD. That's what PhD's do. Get over it. :-)

--
Eric Sosman
eso...@ieee-dot-org.invalid

Lew

unread,
Feb 11, 2010, 2:38:12 PM2/11/10
to

Patricia Shanahan wrote:
>>> [... sensible stuff ...]

Mike Schilling wrote:
>> Good Lord, Patricia, I said "discuss", not "develop the complete
>> theory of"
>> :-)

Eric Sosman wrote:
> She's a PhD. That's what PhD's do. Get over it. :-)

And a genius. That's what geniuses do, too.

(No smiley because it's the simple truth.)

--
Lew

Tom Anderson

unread,
Feb 11, 2010, 3:02:53 PM2/11/10
to
On Wed, 10 Feb 2010, Mike Schilling wrote:

A relaxing of the current rule which didn't ban that would be remiss
indeed.

tom

--
As Emiliano Zapata supposedly said, "Better to die on your feet than
live on your knees." And years after he died, Marlon Brando played him
in a movie. So just think, if you unionize, Marlon Brando might play
YOU in a movie. Even though he's dead. -- ChrisV82

markspace

unread,
Feb 11, 2010, 3:15:43 PM2/11/10
to
Tom Anderson wrote:
> On Wed, 10 Feb 2010, Mike Schilling wrote:
>
>> Suppose the call to "super()" needn't be the first line of a constructor.
>> Discuss the effect and/or legality of the following code:
>>
>> class MyClass extends YourClass
>> {
>> public MyClass(int i)
>> {
>> if ( i > 0)
>> {
>> super(i);
>> }
>> }
>> ...
>
> A relaxing of the current rule which didn't ban that would be remiss
> indeed.


True, but something like this should be acceptable, imo:

class MyClass extends YourClass
{
public MyClass(int i)
{
if ( i > 0)
{
super(i);

} else
{
super();
}
}
...

Because now the object is definitely constructed and also we've done
something useful that the current JLS doesn't allow us to do.

Thomas Pornin

unread,
Feb 12, 2010, 4:43:30 AM2/12/10
to
According to markspace <nos...@nowhere.com>:

> True, but something like this should be acceptable, imo:
>
> class MyClass extends YourClass
> {
> public MyClass(int i)
> {
> if ( i > 0)
> {
> super(i);
> } else
> {
> super();
> }
> }
> ...

Actually it would be acceptable to the JVM. The JVM enforces a call to a
superclass constructor (only one call allowed) before accessing members;
it does so with a control-flow analysis which is very similar to the
analysis which figures out types for local variables, and whether local
variables may be accessed before being initialized. If your code could
be translated to bytecode then things would work.

But the Java compiler enforces the JLS rules, which basically guarantee
that whatever the compiler accepts will also be accepted by the JVM.
This is not a strict equality: in that matter, the JLS is stricter than
the JVM rules.

The bright side is that what you suggest would require only some changes
to the compiler, not the JVM and standard classes, and it would be
backward compatible with existing, deployed JVM.


--Thomas Pornin

Pitch

unread,
Feb 12, 2010, 6:28:38 AM2/12/10
to
In article <hl1ao6$i80$2...@news.albasani.net>, no...@lewscanon.com says...


No it won't, but if is was a method it would.

Pitch

unread,
Feb 12, 2010, 6:32:28 AM2/12/10
to
In article <hl1ban$hes$1...@news.eternal-september.org>,
mscotts...@hotmail.com says...


I though we are talking about changes in the language so it doesn't
mater if it's not a method right now, or if it's allowed only once to be
called. If we are talking of possible changes to Java it could be just
another method and it could be called more than once, ok?

In that case your example works perfectly ok.

Patricia Shanahan

unread,
Feb 12, 2010, 9:39:51 AM2/12/10
to
Pitch wrote:
...

> I though we are talking about changes in the language so it doesn't
> mater if it's not a method right now, or if it's allowed only once to be
> called. If we are talking of possible changes to Java it could be just
> another method and it could be called more than once, ok?
...

That would be the most dangerous possible type of change to the
language, one that changes the semantics of existing syntax.

Currently, the writer of a non-final class can count on exactly one
constructor call per object created, except for "this" calls in the
class code. Multiple constructor calls for the same object, especially
if parameters change between calls, may break invariants such as final
variables being initialized exactly once, and never changing.

Patricia

Pitch

unread,
Feb 12, 2010, 9:59:18 AM2/12/10
to
In article <U5mdnVQN4rmk9ejW...@earthlink.com>,
pa...@acm.org says...

>
> Pitch wrote:
> ...
> > I though we are talking about changes in the language so it doesn't
> > mater if it's not a method right now, or if it's allowed only once to be
> > called. If we are talking of possible changes to Java it could be just
> > another method and it could be called more than once, ok?
> ...
>
> That would be the most dangerous possible type of change to the
> language, one that changes the semantics of existing syntax.

Of course. I don't think this can be changed, I just want people to
agree this restricton should have not be introduced at all.

Patricia Shanahan

unread,
Feb 12, 2010, 10:12:33 AM2/12/10
to

Which restriction are you arguing against? I think the rule that ensures
that a subclass invokes a constructor for its superclass exactly once,
before any use of "this", is a good invariant that simplifies the code
in non-final classes.

On the other hand, I believe that invariant, and a related invariant
ensuring a superclass constructor call before completion other than by
throw, could be enforced while allowing a lot more flexibility in
subclass constructors.

Patricia

Pitch

unread,
Feb 12, 2010, 11:09:45 AM2/12/10
to
In article <87-dnf82RLR-8ujW...@earthlink.com>,
pa...@acm.org says...
>
> Pitch wrote:
> > In article <U5mdnVQN4rmk9ejW...@earthlink.com>,
> > pa...@acm.org says...
> >> Pitch wrote:
> >> ...
> >>> I though we are talking about changes in the language so it doesn't
> >>> mater if it's not a method right now, or if it's allowed only once to be
> >>> called. If we are talking of possible changes to Java it could be just
> >>> another method and it could be called more than once, ok?
> >> ...
> >>
> >> That would be the most dangerous possible type of change to the
> >> language, one that changes the semantics of existing syntax.
> >
> > Of course. I don't think this can be changed, I just want people to
> > agree this restricton should have not be introduced at all.
> >
> >
>
> Which restriction are you arguing against? I think the rule that ensures
> that a subclass invokes a constructor for its superclass exactly once,
> before any use of "this", is a good invariant that simplifies the code
> in non-final classes.

But it complicates the code if you want to change the behaviour of the
initialization process.

Why not leave it up to programmers. We can use a bolean flag if we need
a once-only initialization.


> On the other hand, I believe that invariant, and a related invariant
> ensuring a superclass constructor call before completion other than by
> throw, could be enforced while allowing a lot more flexibility in
> subclass constructors.

And why is it so important to call superclass constructor and have a
fully initialized members of the super class? Every progammer knows that
there is a set of rules for every language and this isn't even a new
rule! It's a good old: "Do not hide virtual methods!" Compilers have
produced similar warnings for ages now. (In this case constructor will
be virtual, of course.)

And what if I don't let the superclass members be initialized? I will
produce an exception probably. Big deal.


Please, look at this example

class A
{
private String data = getData();

protected void getData()
{
return "A";
}
}

class B extends A
{
private String newData = "unknown";

public B(String data)
{
newData = data;
}

protected String getData()
{
return newData;
}
}

When you instantate an object of type B, field A.data will be "unknown"
instead of intended value "A". So the author of class A has allowed the
subclass to change the behaviour of the superclass initailization.

Woudn't it be simpler to put it like this:

class B extends A
{
private String newData = "unknown";

public B(String data)
{
newData = data;
super();
}

protected String getData()
{
return newData;

Joshua Cranmer

unread,
Feb 12, 2010, 12:11:39 PM2/12/10
to

Even C++ requires that superconstructors be called before the
constructor executes (although it does permit you to wrap the whole
initializer in a try-catch block, which was incidentally the feature
that originally prompted this IIRC).

I can't think of a language which treats constructors as regular
methods. C++ lists it as a "special member function", it's one of two
special functions in Java (the other being, essentially, <clinit>). I
think python also treats it specially as well.

It is a very sensible restriction, and the expectation by programmers
coming from other languages is that it will be. Constructors have the
notion of actually reserving the memory space and then initializing it
at the same time--hence we have the `new' keyword and the actual
constructor call. If you were to separate the memory space reservation
and initialization out, then it would make sense to allow constructors
to be called multiple times. But Java doesn't allow you to do so, so the
point is moot.

In any case, I don't agree with the assertion "this restriction should
not have been introduced."
--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth

Mike Schilling

unread,
Feb 12, 2010, 1:35:50 PM2/12/10
to

As I explained above, it breaks all guarantees about class construction.
That's a bad thing.


Patricia Shanahan

unread,
Feb 12, 2010, 2:09:26 PM2/12/10
to

One of the key decisions in language design is how much rope to leave
lying around. A lot of rope makes it easy for programmers to
accidentally hang themselves. Less rope makes accidental hanging less
likely, but makes it harder to do things that need a lot of rope.

Each language has its own trade-off between flexibility and built-in
invariants. Java provides quite a lot of invariants. I use Java when
that is what I want.

I have had situations in which I needed a lot of flexibility and to be
in control. For that, I use C and, if necessary, assembly language.

Patricia

Lew

unread,
Feb 12, 2010, 5:05:24 PM2/12/10
to
mscotts...@hotmail.com says...
>>>> Suppose the call to "super()" needn't be the first line of a constructor.
>>>> Discuss the effect and/or legality of the following code:
>>>>
>>>> class MyClass extends YourClass
>>>> {
>>>> public MyClass(int i)
>>>> {
>>>> if ( i > 0)
>>>> {
>>>> super(i);
>>>> }
>>>> }
>>>> ...

Pitch wrote:
>>> If you look at super() as just another method call it's perfectly ok.

Lew wrote:
>> Constructor calls are not method calls. So that won't work.

Pitch wrote:
> No it won't, but if is was a method it would.

If it was a method none of this thread would have happened. This entire
discussion is about constructors, not methods.

--
Lew

Lew

unread,
Feb 12, 2010, 5:13:52 PM2/12/10
to
Pitch wrote:
> class A
> {
> private String data = getData();

You shouldn't call overridable methods from a constructor.

This would not change even with the ability to put calls before 'super(...)'.

> protected void getData()
> {
> return "A";
> }
> }
>
> class B extends A
> {
> private String newData = "unknown";
>
> public B(String data)
> {
> newData = data;
> }
>
> protected String getData()
> {
> return newData;
> }
> }
>
> When you instantate an object of type B, field A.data will be "unknown"
> instead of intended value "A". So the author of class A has allowed the
> subclass to change the behaviour of the superclass initailization.

Exactly why you aren't supposed to do that sort of thing. Again, putting code
before 'super(...)' would only exacerbate that problem, as your second example
shows.

> Woudn't it be simpler to put it like this:
>
> class B extends A
> {
> private String newData = "unknown";
>
> public B(String data)
> {
> newData = data;
> super();
> }
>
> protected String getData()
> {
> return newData;
> }
> }

No.

You haven't improved anything. The subclass override still changes the
behavior of the superclass constructor. Now you are using the subclass to
alter what should have been an invariant in the superclass, the allocation of
the superclass's private field. Either way you look at it, it's a Bad Idea.

--
Lew

Pitch

unread,
Feb 12, 2010, 7:17:43 PM2/12/10
to
In article <hl4729$j8s$1...@news.eternal-september.org>,

Well, I keep talking hypothetically and you keep sticking with Java.
Nevermind.

Pitch

unread,
Feb 12, 2010, 7:38:33 PM2/12/10
to
In article <hl424b$l5t$1...@news-int.gatech.edu>, Pidg...@verizon.invalid
says...

> > Of course. I don't think this can be changed, I just want people to
> > agree this restricton should have not be introduced at all.
>
> Even C++ requires that superconstructors be called before the
> constructor executes (although it does permit you to wrap the whole
> initializer in a try-catch block, which was incidentally the feature
> that originally prompted this IIRC).

I belive Java picked it up from C.


> I can't think of a language which treats constructors as regular
> methods.

Delphi has virtual constructors but bas class TObject has a non-virtual
empty destructor which you cannot override.

In the other thread I mentioned some .NET languages have this rule, but
some don't like VB.NET, and the compiled code is interchangeable. It is
perfectly ok to use a class with such loose constructor in C# e.g.


> It is a very sensible restriction, and the expectation by programmers
> coming from other languages is that it will be. Constructors have the
> notion of actually reserving the memory space and then initializing it
> at the same time--hence we have the `new' keyword and the actual
> constructor call. If you were to separate the memory space reservation
> and initialization out, then it would make sense to allow constructors
> to be called multiple times. But Java doesn't allow you to do so, so the
> point is moot.


I belive we have three steps in object construction: memory allocation
(new), member initialization, and constructor body execution. Keyword
new is also used in allocating structures bz name or by a pointer.

I can also add that memory allocation means the object is alive at that
moment we have a refetence to this. After is only language specific
implementation.

Pitch

unread,
Feb 12, 2010, 7:38:33 PM2/12/10
to
In article <rpCdnbOlRur1OujW...@earthlink.com>,

Well, you see. I came from Delphi background 10 years ago, and I was
happy to hear they made a new turn a designed a completely new language
based on Delphi (Delphi Prism). Change is good, and I hope some of these
issues came to attention at least to someone.

Another thing. Wherever there is a rule that makes a restriction it
brings up a question why. In this case I would bet that the true reasons
were not about the safety of the language but about the complexity of
implementing it.

I program every day and when I feel something is to complex to design
it's easy to make a compromise and invent a new nifty rule. :)


Ring a bell:
- after construction you must call init() method
- after acquiring a resource, you must release it
- etc..

And remeber this one from the old days:
- after constructing an object you must free it

So they invented GC. So why wouldn't invent marking of resources with
some kind of interface which will release it autamatically after exiting
the scope (like RAII in C++).
So maybe someday they change the fist-line rule...

Pitch

unread,
Feb 12, 2010, 7:43:14 PM2/12/10
to
In article <hl4jr2$g36$1...@news.albasani.net>, no...@lewscanon.com says...

>
> Pitch wrote:
> > class A
> > {
> > private String data = getData();
>
> You shouldn't call overridable methods from a constructor.
>
> This would not change even with the ability to put calls before 'super(...)'.
>
> > protected void getData()
> > {
> > return "A";
> > }
> > }
> >
> > class B extends A
> > {
> > private String newData = "unknown";
> >
> > public B(String data)
> > {
> > newData = data;
> > }
> >
> > protected String getData()
> > {
> > return newData;
> > }
> > }
> >
> > When you instantate an object of type B, field A.data will be "unknown"
> > instead of intended value "A". So the author of class A has allowed the
> > subclass to change the behaviour of the superclass initailization.
>
> Exactly why you aren't supposed to do that sort of thing. Again, putting code
> before 'super(...)' would only exacerbate that problem, as your second example
> shows.

I just wanted to show it is possible in Java to call a method of an
object which is not fully initialized. Why doesn't complier warn about
that? (it's rethorical)

I guess, as Patricia has put it, the rope is too long in this case.
Anyway, I give up. Since there are so many issues concerning a simple
constructor execution, the best way has to be the one we have.

And sorry all if my English was confusing. Godd bless you and Metallica
sucks :)

EOD

Lew

unread,
Feb 12, 2010, 9:50:28 PM2/12/10
to
Pidg...@verizon.invalid

How come you don't use the handle for citations, but the email address? I
know that "pee-djyo" means "beer" in Mandarin, but I really, really had to
work to figure out that you were quoting Joshua Cranmer, who
> says...


>> Even C++ requires that superconstructors be called before the
>> constructor executes (although it does permit you to wrap the whole
>> initializer in a try-catch block, which was incidentally the feature
>> that originally prompted this IIRC).

Pitch wrote:
> I belive Java picked it up from C.

Picked what up? Not constructors, surely.

Joshua:


>> I can't think of a language which treats constructors as regular
>> methods.

Pitch wrote:
> Delphi has virtual constructors but bas class TObject has a non-virtual
> empty destructor which you cannot override.

That doesn't say that Delphi (i.e., Pascal, right?) treats constructors as
regular methods. Does it?

> In the other thread I mentioned some .NET languages have this rule, but
> some don't like VB.NET, and the compiled code is interchangeable. It is
> perfectly ok to use a class with such loose constructor in C# e.g.

That doesn't say that those .NET languages treat constructors as regular
methods. Do they?

Joshua:


>> It is a very sensible restriction, and the expectation by programmers
>> coming from other languages is that it will be. Constructors have the
>> notion of actually reserving the memory space and then initializing it
>> at the same time--hence we have the `new' keyword and the actual
>> constructor call. If you were to separate the memory space reservation
>> and initialization out, then it would make sense to allow constructors
>> to be called multiple times. But Java doesn't allow you to do so, so the
>> point is moot.

Pitch wrote:
> I belive we have three steps in object construction: memory allocation
> (new), member initialization, and constructor body execution. Keyword
> new is also used in allocating structures bz name or by a pointer.

Java?

> I can also add that memory allocation means the object is alive at that
> moment we have a refetence to this. After is only language specific
> implementation.

--
Lew

Mike Schilling

unread,
Feb 12, 2010, 10:30:10 PM2/12/10
to

I would have said that I keep explaining that conventions and rules are
important for keeping software comprehensible and reliable, and you keep
saying "but that gets in the way of hacking".


Tom Anderson

unread,
Feb 13, 2010, 8:03:29 AM2/13/10
to
On Fri, 12 Feb 2010, Joshua Cranmer wrote:

> On 02/12/2010 09:59 AM, Pitch wrote:
>> In article<U5mdnVQN4rmk9ejW...@earthlink.com>,
>> pa...@acm.org says...
>>>
>>> Pitch wrote:
>>> ...
>>>> I though we are talking about changes in the language so it doesn't
>>>> mater if it's not a method right now, or if it's allowed only once to be
>>>> called. If we are talking of possible changes to Java it could be just
>>>> another method and it could be called more than once, ok?
>>> ...
>>>
>>> That would be the most dangerous possible type of change to the
>>> language, one that changes the semantics of existing syntax.
>>
>> Of course. I don't think this can be changed, I just want people to
>> agree this restricton should have not be introduced at all.
>
> Even C++ requires that superconstructors be called before the constructor
> executes (although it does permit you to wrap the whole initializer in a
> try-catch block, which was incidentally the feature that originally prompted
> this IIRC).
>
> I can't think of a language which treats constructors as regular
> methods. C++ lists it as a "special member function", it's one of two
> special functions in Java (the other being, essentially, <clinit>). I
> think python also treats it specially as well.

I can't think of anything special about it in python. Consider:

Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo(object):
... def __init__(self, bar):
... self.bar = bar
...
>>> f = Foo(23)
>>> f.bar
23
>>> f.__init__(17)
>>> f.bar
17
>>> class Bar(Foo):
... def __init__(self, qux):
... self.qux = qux
...
>>> b = Bar("fnord!")
>>> b.qux
'fnord!'
>>> b.bar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Bar' object has no attribute 'bar'

That is, you can call an __init__ method on an already-constructed object,
and construction doesn't implicitly call the superclass __init__. There's
the special semi-magic super function (actually, a class) that you have to
use if you want to invoke a superclass __init__ function.

I suppose the subtlety is that __init__ isn't a constructor - it's an
initialisation method. It gets called by the construction code, but it's
just a normal function itself.

tom

--
First man to add a mixer get a shoeing! -- The Laird

0 new messages