Skip to content

A constructor initialiser naming the base class only reaches the base constructor in C++ and JavaScript; Python, C#, Go, Rust and C treat it as a field #169

Description

@matt-edmondson

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:

Target Output Code
Python self.Shape = 0. An explicit derived constructor never calls super().__init__(); only the synthesised one does PythonGenerator.cs L563-611, L681-695
C# this.Shape = 0; and no : base(...) CSharpGenerator.cs L685-697
Go Circle{Shape: 0, radius: radius} GoGenerator.cs L1146-1160
Rust Self { Shape: 0, radius }, but the base field is base RustGenerator.cs L1062-1081
C { .Shape = 0, .radius = radius }, but the member is Shape base; CGenerator.cs L278-296

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).

Activity

  1. matt-edmondson commented on Oct 6, 2026

    @matt-edmondson
    ContributorAuthor

    Triage


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions