4.8 Class Namespaces
A name defined by class works as a namespace to access field selectors and methods of the class. It also works like the namespace form, because the body of a class can include export forms to export additional bindings. Other definitions can also be written in the class body, and those definitions are accessible outside the class only if they are exported.
> Posn.get_origin()
Posn(0, 0)
There’s a subtlety, however, when definitions within the class body try to refer to the class. Unless the reference is sufficiently nested or late enough in the class body, it can’t work, because the class is not defined until enough of the class body forms are processed.
> class Posn(x, y):
export:
origin
Posn: undefined;
cannot reference an identifier before its definition
In this example, the solution can be simply to move the export declaration earlier:
> class Posn(x, y):
export:
origin
> Posn.origin
Posn(0, 0)
This change works because definitions and expressions in a class body are effectively moved after the class’s definition when there is no class clause or declaration form afterward. Moving the export declaration form before the definition of origin means that Posn can be defined before origin’s right-hand side is evaluated.
A related way around the problem is to not put the definition inside the class, but still export it from the class. Just like in namespace, an export form in class can export any binding that is visible in the environment, including things defined outside the class form.
The only drawback with this strategy is that the inferred name in a definition (typically for error-reporting purposes) will not have the class name as a prefix automatically.
Yet another solution is to use class.together, as described in the next section, but putting helper definitions at the end of the class body or after the class can avoid a small amount of overhead for instance checks.