Allowing super() calls to come later in subclass constructors
Neal Gafter
neal at gafter.com
Mon Nov 9 16:48:02 PST 2009
In addition to the things you've shown are allowed, the VM specification
allows the code to assign to fields of "this" before the superclass
constructor. That's necessary in some cases to generate correct code for
inner classes.
The only difficulty with your proposal is that writing the specification to
describe exactly what can and cannot be done in that code (and implementing
it) will be cumbersome. For example, does the superclass constructor
invocation have to be at the top level, or can it be nested within an "if"
statement (with a possibly different one within the else clause)? Is this
worth the effort, when that effort could be put elsewhere?
Cheers,
Neal
On Mon, Nov 9, 2009 at 3:41 PM, Derrick Rice <derrick.rice at gmail.com> wrote:
> Hi all,
>
> I have a question regarding the requirement for constructor calls to
> be the first statement from other constructors. If I'm asking in the
> wrong place, please correct me and I apologize in advance. I
> considered carefully before emailing, but I found no other discussion
> areas which get into this level of detail or have the experience I
> expect to find here.
>
> My question boils down to: Why is it forbidden to perform local (i.e.
> stack or non-instance) operations prior to calling a constructor? Is
> this an enhancement worth making?
>
> Currently, the first call in any subclass constructor must be a call
> to the super constructor (or the implicit super()) or a call to
> another constructor. I would like to present a case where this is
> inconvenient at the least and encourages poor workarounds.
>
> Consider the following situation that has no difficulties. A is a
> class which takes as an argument another nontrivial object. B is a
> subclass which intends to abstract away the complexity of A's
> argument. The example is oversimplified - imagine the compoundThing
> is sufficiently complicated to create and it is useful to abstract it
> away for a special case (namely, B).
>
> class A{
> A( ArgType compoundThing) {... }
> }
>
> class B extends A{
> B( OtherType one, OtherType two ) {
> super ( new ArgType(one, two, "constantThree") )
> }
> }
>
> This works great. Now suppose that B wants to hold on to the argument
> which it passes to super(). It seems like it should be able to, since
> it had created the object to begin with. Ideally we'd just say foo =
> new ArgType(...) and then super(foo) but this isn't permitted. So we
> can do this...
>
> class B extends A{
> B( OtherType one, OtherType two) {
> this(new ArgType(one, two, "constantThree")
> }
> private B (ArgType compoundThing){
> super(compoundThing)
> Object foo = compoundThing
> }
> }
>
> In order to keep a handle to the object that I created in the
> constructor, I have to create an entirely new constructor so that it
> is stored on the stack as an argument. That looks like poor form.
>
> Now suppose I also want to do input validation on B's arguments prior
> to calling the constructor. Ideally I'd just want to do this before
> calling super(...) but I could do this instead...
>
> class B extends A{
> B ( OtherType one, OtherType two){
> this(one, two, B.checkArgs(one, two))
> }
> private B (OtherType one, OtherType two, Object ignore){
> super( new ArgType(one, two, "constantThree") )
> }
> static Object checkArgs(OtherType one, OtherType two){
> if(one==null || two==null)
> throw new IllegalArgumentException()
> return null
> }
> }
>
> Now I've created a new constructor AND a static method that, in my
> opinion, are useless. If I combined this with the above solution, I'd
> have 2 extra constructors and a static method where I'd rather just
> have:
>
> class B extends A{
> B ( OtherType one, OtherType two){
> if(one==null || two==null)
> throw new IllegalArgumentException()
> Object foo = new ArgType(one, two, "constantThree")
> super(foo)
> }
> }
>
> I think I've demonstrated that anything you want to do without
> touching `this` or `super` prior to calling a constructor can be
> accomplished through these ugly workarounds.
>
> Is it not reasonable to allow these operations to precede the constructor
> calls?
>
> Thanks,
>
> Derrick
>
> P.S. I'm sorry that this email was so long, but I wanted to clearly
> demonstrate that this would be syntactic sugar and how it's absence
> can lead to some very poor looking code. I hope it has been a
> worthwhile read and thank you for your patience.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20091109/11e272b5/attachment.html
More information about the compiler-dev
mailing list