Allowing super() calls to come later in subclass constructors

Derrick Rice derrick.rice at gmail.com
Mon Nov 9 15:41:17 PST 2009


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.



More information about the compiler-dev mailing list