What's wrong
A MemberInitialiser named after the class's BaseType is the C++ : Base(args) idiom. C++ writes it into its initialiser list. JavaScript was fixed to honour it in #156 (for #103), in JavaScriptGenerator.WriteSuperCall. The other five generators treat it as an ordinary member named after the base:
Reproduction (at 1d544a3)
The fixture has two classes:
Shape: field sides, constructor Shape(int sides) with initialiser sides = sides.
Circle : Shape: field radius, constructor Circle(double radius) with initialisers Shape = 0 and radius = radius.
This is the JS DerivedClassFile fixture plus MemberInitialiser("Shape").
Results per target:
- C++:
: Shape(0), radius(radius), which is correct.
- JavaScript:
super(0);, which is correct.
- Python: running the generated code,
Circle(1.0).sides raises AttributeError: 'Circle' object has no attribute 'sides', because Shape.__init__ never ran.
- Go:
go vet reports cannot use 0 (untyped int constant) as Shape value in struct literal.
- C#: CS1061, since there is no member
Shape. Without : base(0) it also hits CS7036, since Shape has no parameterless constructor.
- Rust: E0560, since there is no field
Shape.
- C: compile error, since there is no struct member
Shape.
Why it matters
A derived class whose base needs constructor arguments can't be expressed portably in five of the seven targets. In Python the failure is silent until a base field is read. This is the same class of bug as #103, fixed there for JS only.
Suggested fix
- Move the base-initialiser lookup out of
JavaScriptGenerator.WriteSuperCall into StandardLanguageGenerator, and make it reachable from the C# generator too. The rule: an initialiser whose Name equals BaseType.Name.
- Skip that initialiser when writing members, and emit the base call in each target's form:
- Python:
super().__init__(args) as the first statement of every derived constructor, with no arguments when there's no base initialiser.
- C#:
: base(args).
- Go:
Shape: NewShape(args).
- Rust:
base: Shape::new(args).
- C:
.base = Shape_create(args).
Acceptance criteria
Related: #149 (the synthesised Python __init__ hides the base constructor when the derived class has no constructor of its own) and #103 (the JS-only version of this bug).
What's wrong
A
MemberInitialisernamed after the class'sBaseTypeis the C++: Base(args)idiom. C++ writes it into its initialiser list. JavaScript was fixed to honour it in #156 (for #103), inJavaScriptGenerator.WriteSuperCall. The other five generators treat it as an ordinary member named after the base:self.Shape = 0. An explicit derived constructor never callssuper().__init__(); only the synthesised one doesthis.Shape = 0;and no: base(...)Circle{Shape: 0, radius: radius}Self { Shape: 0, radius }, but the base field isbase{ .Shape = 0, .radius = radius }, but the member isShape base;Reproduction (at
1d544a3)The fixture has two classes:
Shape: fieldsides, constructorShape(int sides)with initialisersides = sides.Circle : Shape: fieldradius, constructorCircle(double radius)with initialisersShape = 0andradius = radius.This is the JS
DerivedClassFilefixture plusMemberInitialiser("Shape").Results per target:
: Shape(0), radius(radius), which is correct.super(0);, which is correct.Circle(1.0).sidesraisesAttributeError: 'Circle' object has no attribute 'sides', becauseShape.__init__never ran.go vetreportscannot use 0 (untyped int constant) as Shape value in struct literal.Shape. Without: base(0)it also hits CS7036, sinceShapehas no parameterless constructor.Shape.Shape.Why it matters
A derived class whose base needs constructor arguments can't be expressed portably in five of the seven targets. In Python the failure is silent until a base field is read. This is the same class of bug as #103, fixed there for JS only.
Suggested fix
JavaScriptGenerator.WriteSuperCallintoStandardLanguageGenerator, and make it reachable from the C# generator too. The rule: an initialiser whoseNameequalsBaseType.Name.super().__init__(args)as the first statement of every derived constructor, with no arguments when there's no base initialiser.: base(args).Shape: NewShape(args).base: Shape::new(args)..base = Shape_create(args).Acceptance criteria
sidesis set.__init__.Related: #149 (the synthesised Python
__init__hides the base constructor when the derived class has no constructor of its own) and #103 (the JS-only version of this bug).