How does a child object hold a reference back to its parent when the parent creates it in its constructor?

← Classes and OOP · Ref: Q2181

Use the PARENT LINK. Declare the child property unset ('section as Part?'). In the constructor, set every OTHER property first, then assign the child a dynamic class (or dynamic function) whose capture list captures 'this':

  Document()
    -> text as String
    title: text
    section :=? (owner: this) with trait of Part as class
      override describe() as pure
        <- rtn as String: `a section of '${owner.title()}'`
      default operator ?

The object is complete as soon as that assignment finishes; from then on the child may be used freely, and it holds the parent object itself, not a copy - after 'doc.retitle("Handbook")' the section describes the new title.

WHY 'this' IS ALLOWED HERE WHEN IT IS NOT ELSEWHERE
EK9 builds objects in two phases: first every property is given a value, then the object may be used (Q2180, Q1396). Using an incomplete object is forbidden because something might READ a property that has no value yet. Capturing 'this' into a NEW child that is stored in one of the parent's OWN properties reads nothing: none of the child's methods has run, and nothing outside the object holds it - the object only holds itself, exactly as 'me: this' does (Q1471). So EK9 treats that one statement as a store, not a use. It is the only leniency in the rule, and it covers only this shape: a dynamic class or function capturing 'this' that is the whole right-hand side of ':=?', ':=' or ':' to one of the type's own properties ('this.section :=? ...' works as the target too).

THE CATCH-22 IT SOLVES

The child needs the parent, and the parent is not complete until it has the child. Without the leniency neither could go first; with it, the child is created by the very statement that completes the parent.

THE ONE CONDITION

Every other property must already be set on that path through the constructor - or be the target of a LATER capture-assignment, which is how two children work (Q2182). Here 'title' is set first. If 'title' were set after 'section', the object would stay incomplete beyond this one statement, the child would have been handed a parent with no title, and E08061 says so: "'this' is captured into 'section' before 'title' is set".

WHAT STAYS FORBIDDEN

Until the object is complete the property holding the child IS the object under another name, so calling it, passing it or capturing it again too early is E08061; a dynamic class created this way may not use its owner in its own property initialisers (they run during the capturing statement); and an open or abstract type never hands out 'this' from its constructor (all three: Q2183). Passing the child to another object's method from the constructor publishes the parent, just as passing 'this' does (E08250).

Example

defines module qa.oop.parent.link

  defines trait

    Part
      describe() as pure
        <- rtn as String?

  defines class

    Document
      title as String?
      section as Part?

      default private Document()

      Document()
        -> text as String
        title: text
        section :=? (owner: this) with trait of Part as class
          override describe() as pure
            <- rtn as String: `a section of '${owner.title()}'`
          default operator ?

      title() as pure
        <- rtn as String: title

      retitle()
        -> text as String
        title: text

      section()
        <- rtn as Part: section

      default operator ?

  defines program

    ParentLink()
      stdout <- Stdout()
      doc <- Document("Guide")
      part <- doc.section()
      stdout.println(part.describe())

      //The section holds the document itself, not a copy: it sees the new title.
      doc.retitle("Handbook")
      stdout.println(part.describe())

Common mistakes

E08061 — Capturing 'this' into an own property is allowed only when every other property is already set (or is itself set by a later capture). Here 'title' is still unset, so the section would be handed a parent with no title. Set 'title' first, then create the section.

Incorrect:

section :=? (owner: this) with trait of Part as class
          override describe() as pure
            <- rtn as String: `a section of '${owner.title()}'`
          default operator ?
        title: text

Correct:

title: text
        section :=? (owner: this) with trait of Part as class
          override describe() as pure
            <- rtn as String: `a section of '${owner.title()}'`
          default operator ?
Other ways to ask this
  • How do I give a child object a parent reference in EK9?
  • How do I create a back reference from a child to its owner in a constructor?
  • Can I use this in a constructor to build a child that points back to the parent?
  • Is capturing 'this' in a dynamic class inside a constructor leaking this?
  • Why is '(owner: this)' in my constructor E08061 until the other properties are set?

Coming from another language?

Java: 'this.section = new Section(this);' compiles anywhere in the constructor, and the Section may call back into a parent whose later fields are still null. Kotlin: the same, with a 'Leaking this' warning. Swift: 'self' cannot be passed anywhere until every stored property is initialised, so a parent link is declared as an optional or implicitly unwrapped property and assigned after phase one - EK9 allows the child to be created as the LAST step of phase one, and only through a capture stored in the parent's own property. Rust: a back reference needs Rc/Weak. EK9: the compiler proves no half-built parent is ever read.

Keywords: owner, back reference, leaking this, child, capture, parent reference, dynamic class, constructor, E08061, parent link, two-phase