From: Alessio Stalla on
On Feb 10, 1:43 am, Roedy Green <see_webs...(a)mindprod.com.invalid>
wrote:
> On Tue, 09 Feb 2010 16:22:35 +0000, Steven Simpson <s...(a)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
From: Pitch on
In article <b366f0eb-11ae-48bb-86b1-67eff9b81a88
@k41g2000yqm.googlegroups.com>, alessiostalla(a)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
From: Tom Anderson on
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
From: Tom Anderson on
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
From: Mike Schilling on
Tom Anderson wrote:
> 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!

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