Skip to content

Pull Up Constructor Body

Pull Up Constructor Body is Pull Up Method applied to the one method with special rules: the constructor. When several sibling subclasses begin their constructors with the same field-setting code, that shared initialization moves into the superclass constructor. Each subclass constructor then calls up to the parent for the common part and keeps only the lines unique to itself.

Open two sibling subclasses and their constructors start identically: this.name = name; this.id = id; this.hiredAt = now(); repeated verbatim, line for line. It is Duplicated Code in the most load-bearing place — object setup. Add a field to the base concept tomorrow and you must remember to wire it through every subclass constructor. The common setup belongs to the shared concept, so it belongs in the shared constructor.

Manager and Engineer both initialise name and id themselves. After, the superclass constructor owns that, and each subclass calls up before doing its own bit.

// Before — each subclass constructor repeats the common setup
class Employee {
name!: string;
id!: string;
}
class Manager extends Employee {
reports: string[];
constructor(name: string, id: string, reports: string[]) {
super();
this.name = name; // duplicated
this.id = id; // duplicated
this.reports = reports;
}
}
class Engineer extends Employee {
stack: string;
constructor(name: string, id: string, stack: string) {
super();
this.name = name; // duplicated
this.id = id; // duplicated
this.stack = stack;
}
}
// After — the superclass constructor owns the common fields
class Employee {
constructor(public name: string, public id: string) {}
}
class Manager extends Employee {
constructor(name: string, id: string, public reports: string[]) {
super(name, id);
}
}
class Engineer extends Employee {
constructor(name: string, id: string, public stack: string) {
super(name, id);
}
}
classDiagram
  class Employee {
    +name: string
    +id: string
    +Employee(name, id)
  }
  class Manager {
    +Manager(name, id, reports)
  }
  class Engineer {
    +Engineer(name, id, stack)
  }
  Employee <|-- Manager : super(name, id)
  Employee <|-- Engineer : super(name, id)
Common field setup moves into the Employee constructor; subclasses call up to it
  1. Add a constructor on the superclass if it lacks one. Give it parameters for the fields the subclasses set identically.
  2. Move the shared assignment lines into that superclass constructor.
  3. In each subclass constructor, replace those lines with a call up to the parent — super(...) in TypeScript/Python — passing the common arguments.
  4. Make sure the call-up happens first, before the subclass touches any field, since field setup depends on the base being initialised.
  5. Run your tests. Constructed objects must hold the same field values as before.
  6. Watch for ordering hazards: if subclasses ran the common code at different points relative to their own logic, reconcile that before pulling up.

Reach for this whenever sibling constructors share a prefix of identical initialization. Centralising it means a new shared field is wired through in exactly one place, and the subclass constructors shrink to just what makes each type distinct.

The catch is the constructor’s strict rules: the call up to the parent must run before the subtype uses any inherited field, and if the siblings interleaved common and specific setup in different orders, you must untangle that first — sometimes the safer route is to extract the common work into a helper the constructors call rather than into the constructor itself. In Go and Rust there is no constructor to pull up: you express the same intent with a shared constructor function plus embedding (Go) or a held base struct (Rust), so the common setup still lives in exactly one place.

When is Pull Up Constructor Body the right move?
In TypeScript and Python, how does a subclass constructor reuse the pulled-up setup?
What ordering rule must you respect when pulling up a constructor body?
How do Go and Rust express this intent without inheritance?