Users › 02 Program structure

Program structure

Understand how files, names, imports and visibility fit together before writing real classes.

1. One primary declaration per file

A file starts with exactly one primary directive, followed by its members:

%class com.example.Parser
    // fields, constructors, methods

%sub Lexer
    // a file-private helper class

%sub Token
    // another one
DirectiveMeaningImplementationInstances
%classpublic classLopolithmany
%interfaceinterfaceLopolith
%simplesingleton classLopolithexactly one
%nativeclass implemented in a .soC pluginmany
%nativesimplenative singletonC pluginexactly one

2. The path is the name

For %class, %interface, %simple and the native forms, the file path mirrors the fully-qualified name:

com/example/Parser.loth   ⇄   %class com.example.Parser

The compiler checks this both for the file you compile and for every dependency it loads by name. The one exception is the file you pass on the command line, which may live anywhere.

3. Imports

%class com.example.Main
    #import com.example.Parser
    #import miao.Test as T
    #importlocal Helper

    // fields and methods below

Once a module is loaded (directly or transitively) you may also refer to its classes by full name without an import. Short names still need an import.

4. Visibility

EntityDefaultPublicPrivate
Fieldprivate to the classpubdefault
Methodpublicdefault_ prefix
Interface memberalwaysnot allowed
%sub memberfile-wide
Typepublicdefault%sub (file only)

Fields are private unless marked pub, and methods are public unless their name starts with _. Field access always goes through this., even inside the class.

5. Private helpers with %sub

%sub declares a class that lives inside one file. Define it as %sub Name, use it as $Name. Its members are all file-wide public (no pub, no _), it can implement interfaces and have constructor overloads, and it never appears in a public signature. It is the replacement for anonymous or one-off classes.

%simple com.example.structure.Demo implements Main
    int run(int argc, String[] argv) Main@run {
        $Point p = new $Point(2, 3)
        return p.sum() == 5 ? 0 : 1
    }

%sub Point
    int x
    int y

    void ___init(int x, int y) {
        this.x = x
        this.y = y
    }

    int sum() {
        return this.x + this.y
    }

(This program produces no output; it only has to exit with code 0.)

6. Comments

// one line

/* several
   lines */