From: Alessio Stalla on 10 Feb 2010 03:33 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 10 Feb 2010 10:45 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 10 Feb 2010 14:09 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 10 Feb 2010 16:57 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 10 Feb 2010 17:00
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. |