2.8 :clean()

This method can be used to clean up the objects of a dialog or module (release of previously allocated resources) before they are finally destroyed. The method is predefined on all objects, Models and Defaults, but may be overwritten to carry out custom actions on the objects.

The :clean() method cannot be invoked explicitly. It is only called implicitly:

  1. If a dialog or module is to be unloaded, the :clean() method is called for all objects, Models and Defaults of the dialog or module after the finish rule.
  2. If an object or model is destroyed at runtime (calling the :destroy() method, built-in function destroy() or the interface function DM_Destroy() or DMcob_Destroy()), the :clean() method is invoked for that object immediately before it is destroyed.

Definition

void :clean
(
)

Parameters

None.

Redefinition

To redefine the method, it is sufficient to simply write the following at an object:

window W {
  :clean()
  {
    ...
    // Code to release things or bring data into consistent state.
    ...
  }
}

In order to delegate some of the tasks to the superclass, this:super() can be used to call the :clean() method of the Model or Default further up in the inheritance hierarchy.

Note

Calling this:super() has another important function for the :clean() method. If this method is called at the top level (typically the Default), even if there is no more formal superclass, the :clean() methods on the children of the object will also be invoked. Hence, invocations of the :clean() methods on the children can be suppressed if somewhere in the inheritance hierarchy there is no call of this:super().

Example

dialog CLEAN

default record {
  :clean() {
    print "== DEFAULT >>>";
    this:super();
    print "== DEFAULT <<<";
  }
}

model record MRec1 {
  :clean() {
    print "== MRec1 >>>";
    this:super();
    print "== MRec1 <<<";
  }

  child record R1 {
    :clean() {
      print "== R1 >>>";
      this:super();
      print "== R1 <<<";
    }
  }
  child record R2 {
    :clean() {
      print "== R2 >>>";
      this:super();
      print "== R2 <<<";
    }
  }
}

model MRec1 MRec2 {
  :clean() {
    print "== MRec2 >>>";
    // No call of this:super().
    print "== MRec2 <<<";
  }
}

model MRec1 MRec3 {
  // Here the predefined :clean() method comes into action.
  child record R3 {
    :clean() {
      print "== R3 >>>";
      this:super();
      print "== R3 <<<";
    }
  }
}

on dialog start
{
  variable object O;

  O := MRec2:create(CLEAN);
  print "on start: Destroy";
  O:destroy();
  // No :clean() of children R1 and R2.

  O := MRec3:create(CLEAN);
  print "on start: Destroy";
  O:destroy();
  // :clean() methods of children R1, R2 and R3 are invoked.

  exit();
}

The modified section from the trace file should illustrate what happens when this code is executed.

"on start: Destroy"
    "== MRec2 >>>"
    "== MRec2 <<<"
// No :clean() of children R1 and R2.

"on start: Destroy"
    "== MRec1 >>>"
        "== DEFAULT >>>"
      "== R1 >>>"
          "== DEFAULT >>>"
          "== DEFAULT <<<"
      "== R1 <<<"
      "== R2 >>>"
          "== DEFAULT >>>"
          "== DEFAULT <<<"
      "== R2 <<<"
      "== R3 >>>"
          "== DEFAULT >>>"
          "== DEFAULT <<<"
      "== R3 <<<"
        "== DEFAULT <<<"
    "== MRec1 <<<"
// :clean() methods of children R1, R2 and R3 are invoked.