|
Hi,
Simple scala code: class Calc( val intr: Double) generates: // Compiled from Simple.scala (version 1.5 : 49.0, super bit) public class lifecalc.math2.Calc implements scala.ScalaObject { // Field descriptor #4 D private final double intr; // Method descriptor #6 (D)V // Stack: 3, Locals: 3 public Calc(double intr); 0 aload_0 [this] 1 dload_1 [intr] 2 putfield lifecalc.math2.Calc.intr : double [12] 5 aload_0 [this] 6 invokespecial java.lang.Object() [17] 9 return Line numbers: [pc: 0, line: 3] Local variable table: [pc: 0, pc: 10] local: this index: 0 type: lifecalc.math2.Calc [pc: 0, pc: 10] local: intr index: 1 type: double . . . As far I understand super() must be called first, but in bytecode 2 putfield lifecalc.math2.Calc.intr : double [12] is executed first and super() invoked later 6 invokespecial java.lang.Object() [17] Java code public class Calc { private final double intr; public Calc(double intr) { this.intr = intr; } } generates: // Compiled from Calc.java (version 1.5 : 49.0, super bit) public class jalab.Calc { // Field descriptor #6 D private final double intr; // Method descriptor #8 (D)V // Stack: 3, Locals: 3 public Calc(double intr); 0 aload_0 [this] 1 invokespecial java.lang.Object() [13] 4 aload_0 [this] 5 dload_1 [intr] 6 putfield jalab.Calc.intr : double [15] 9 return Line numbers: [pc: 0, line: 7] [pc: 4, line: 8] [pc: 9, line: 9] Local variable table: [pc: 0, pc: 10] local: this index: 0 type: jalab.Calc [pc: 0, pc: 10] local: intr index: 1 type: double } Scala code works but AspectJ throws error: Exception in thread "main" java.lang.VerifyError: (class: lifecalc/math2/Calc, method: <init> signature: (D)V) Expecting to find object/array on stack at lifecalc.math2.Simple$.main_aroundBody2(Simple.scala:8) at lifecalc.math2.Simple$$AjcClosure3.run(Simple.scala:1) at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:101) May be Scala initialization order is worng? I am using Eclipse 3.2.2 and Scala plugin 2.7.1.r15152-b20080522020257 Cheers, toivo |
|
No, this behaviour is valid. You can assign to fields in the current
class before invoking a superconstructor. If AspectJ is getting confused by it, that's a bug in AspectJ. From the Java Virtual Machine Specification ( http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html ): 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. On Fri, Aug 22, 2008 at 11:40 AM, toivo <[hidden email]> wrote: > > Hi, > > Simple scala code: > > class Calc( val intr: Double) > > generates: > > // Compiled from Simple.scala (version 1.5 : 49.0, super bit) > public class lifecalc.math2.Calc implements scala.ScalaObject { > > // Field descriptor #4 D > private final double intr; > > // Method descriptor #6 (D)V > // Stack: 3, Locals: 3 > public Calc(double intr); > 0 aload_0 [this] > 1 dload_1 [intr] > 2 putfield lifecalc.math2.Calc.intr : double [12] > 5 aload_0 [this] > 6 invokespecial java.lang.Object() [17] > 9 return > Line numbers: > [pc: 0, line: 3] > Local variable table: > [pc: 0, pc: 10] local: this index: 0 type: lifecalc.math2.Calc > [pc: 0, pc: 10] local: intr index: 1 type: double > . . . > > As far I understand super() must be called first, but in bytecode > > 2 putfield lifecalc.math2.Calc.intr : double [12] > > is executed first and super() invoked later > 6 invokespecial java.lang.Object() [17] > > Java code > public class Calc { > > private final double intr; > > public Calc(double intr) { > this.intr = intr; > } > } > > generates: > > // Compiled from Calc.java (version 1.5 : 49.0, super bit) > public class jalab.Calc { > > // Field descriptor #6 D > private final double intr; > > // Method descriptor #8 (D)V > // Stack: 3, Locals: 3 > public Calc(double intr); > 0 aload_0 [this] > 1 invokespecial java.lang.Object() [13] > 4 aload_0 [this] > 5 dload_1 [intr] > 6 putfield jalab.Calc.intr : double [15] > 9 return > Line numbers: > [pc: 0, line: 7] > [pc: 4, line: 8] > [pc: 9, line: 9] > Local variable table: > [pc: 0, pc: 10] local: this index: 0 type: jalab.Calc > [pc: 0, pc: 10] local: intr index: 1 type: double > } > > Scala code works but AspectJ throws error: > Exception in thread "main" java.lang.VerifyError: (class: > lifecalc/math2/Calc, method: <init> signature: (D)V) Expecting to find > object/array on stack > at lifecalc.math2.Simple$.main_aroundBody2(Simple.scala:8) > at lifecalc.math2.Simple$$AjcClosure3.run(Simple.scala:1) > at > org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:101) > > May be Scala initialization order is worng? > I am using Eclipse 3.2.2 and Scala plugin 2.7.1.r15152-b20080522020257 > > Cheers, > toivo > > > -- > View this message in context: http://www.nabble.com/Object-initialization-order-in-Scala-tp19104940p19104940.html > Sent from the Scala mailing list archive at Nabble.com. > > |
|
In reply to this post by toivo-2
toivo wrote:
> May be Scala initialization order is worng? No, that is the correct initialization order. Constructor arguments will be initialized before the object is initialized. |
|
In reply to this post by toivo-2
On Fri, Aug 22, 2008 at 03:40:06AM -0700, toivo wrote:
> class Calc( val intr: Double) > public Calc(double intr); > 0 aload_0 [this] > 1 dload_1 [intr] > 2 putfield lifecalc.math2.Calc.intr : double [12] > 5 aload_0 [this] > 6 invokespecial java.lang.Object() [17] > 9 return > May be Scala initialization order is worng? As already explained, the order is intentional. Here's some motivation for it: instead of writing abstract class A(i : Int) { ... initialize using i ... } abstract class B(i : Int) extends A(i) { ... } class C(i : Int) extends B(i) { ... } you can write abstract class A { val i : Int; ... initialize using i ... } abstract class B extends A { ... } class C(val i : Int) extends B Since the constructor of C initializes the field i before calling the superclass constructor, the constructor of A can use i during normal initialization. This is also what early definitions are used for. An advantage, in addition to the neater syntax (no need to relay the constructor arguments all the way to the base class), is that the latter style also works with traits and multiple inheritance, whereas constructors can only be used with true classes. (Btw, is there some established nomenclature: what do you call non-trait classes, and what do you call traits and non-trait classes together?) Personally, I never use constructor parameters, precisely because of their inflexibility. Instead, I use abstract value members which are defined during object creation. Or, if a level of abstraction is required, I use factory methods in the companion object. Lauri |
|
I think the SLS uses the term "template" to cover the definition of classes traits and objects. I wouldn't call it established nomenclature though, and programmers are likely to think of some kind of text/html templating system, a macro system like Template Haskell, or C++ templates if you just drop it casually into conversation.
5.1 Templates Syntax: ClassTemplate ::= [EarlyDefs] ClassParents [TemplateBody] TraitTemplate ::= [EarlyDefs] TraitParents [TemplateBody] ClassParents ::= Constr {'with' AnnotType} TraitParents ::= AnnotType {'with' AnnotType} TemplateBody ::= [nl] '{' [SelfType] TemplateStat {semi TemplateStat} '}' SelfType ::= id [':' Type] '=>' | this ':' Type '=>' A template defines the type signature, behavior and initial state of a trait or class of objects or of a single object. On Fri, Aug 22, 2008 at 4:35 AM, Lauri Alanko <[hidden email]> wrote:
|
| Powered by Nabble | Edit this page |
