The site sections are under development.

The materials may be incomplete or contain errors. The site content will be synchronized with the implementation in the next release, while the current version (0.6.0) is intended for syntax prototyping and for creating the playground.

Code hierarchy

Namespaces, modules and packages

Namespaces

TrustLang supports namespaces; the separator, as in C++, is the double colon ::. A namespace can be specified both for an individual identifier and for a whole code block.

Unlike namespace in C++, namespaces in TrustLang serve not only to organize code into logical groups and to avoid name conflicts: a name in which a namespace is explicitly specified refers to static objects (memory for which is allocated at compile time).

A global name cannot be shadowed by a macro or a local variable during name lookup. To create a global (static) variable, it is enough to write its name with the global qualifier ::var. The namespace for a code block is specified before the opening curly brace (ns:: { ... };).

::var := 0;    # global variable (not shadowed by a macro/local)

ns:: {          # namespace ns
    a:Int32 := 2;   # ns::a
    sub:: {         # nested namespace
        c:Int32 := 3;   # ns::sub::c
    };
};

Modules

TrustLang implements program modules and packages: the idea of hierarchical file placement in file-system directories (as in Python), but the name separator is not a dot, but a backslash \.

A module name may contain only lowercase English letters, digits and the underscore character (except the first and last positions). The restriction is due to the direct mapping of module names onto file-system objects: different file systems may have different encodings and case requirements.

A module is understood as a file with source code (the *.src extension). Modules store frequently used functions, classes, constants, etc. They are conventionally divided into modules and programs: programs are intended for direct launch, modules — for import into other programs (functionally they do not differ).

Module objects

All objects defined inside one module without specifying a global namespace are visible only within the current file and in modules connected after its definition.

The lifetime of static and local variables of the top level of a module is the same and is limited by the lifetime of the module itself, but for multithreading they differ: a static module variable always exists in a single instance for all threads, while a local module variable is its own for each thread (an analog of thread_local in C++11).

Importing modules

A relative module name starts with one \ character and points to a file relative to the current module. An absolute name starts with \\ and points to a file relative to the directory of the current executable file (or the module search directories, which can be overridden, for example, by command-line arguments).

The simplest way to import a module is to write its name with parentheses as a function call; in the parentheses you can pass module initialization arguments, the list of imported functions, etc. If the module name is preceded by the preprocessor character (@\dir\module()), the module imports not only code but also its macros (only with static loading).

Modules can be loaded statically or dynamically (by analogy with static and dynamic linking of libraries):

  • \dir\module() — static loading by relative path;
  • @\dir\module() — static loading with macro import;
  • \\root\dir\module() — static loading by absolute path;
  • \\( "dir\file" ) — dynamic loading at runtime (with dynamic linking macros cannot be imported).

With dynamic loading, the compilation of the module and all checks are performed at application runtime; static loading allows detecting possible errors at compile time.

Besides import by source text, TrustLang describes a semantic ABI — a way of representing a compiled module in which binary symbols are bound to a typed semantic definition, while the matching of objects is performed by the language compiler. The principle is described in Semantic ABI of modules.

Packages

A package is a directory that includes other directories and modules and contains an additional file __init__.src. Packages are used as a complement to namespaces and allow working with modules through specifying the nesting level. Unlike Python and Java, where modules/packages replace namespaces, in TrustLang the modular structure and namespaces are used simultaneously and, when specifying a full name, are combined: \root\dir\module::ns::name::var, where root and dir are directories relative to the current module, module is the file name (root/dir/module.src).

The file __init__.src, unlike Python, cannot be empty — it must explicitly load the modules that belong to the package:

\simper();
\compper();
\annuity();

Package import uses the same syntax as module import. An example of the package fincalc (__init__.src + modules simper.src, compper.src, annuity.src):

\fincalc();                 # import the whole package
\fincalc\simper();          # import a single module
sp := \fincalc\simper();    # import a module with an alias
\fincalc\simper(__import__="fv");  # import a specific function

Namespaces and classes

In TrustLang, decoration (mangling) of names by argument types is not used. Class methods (when OOP is implemented) get unique identifiers by analogy with Python: a global function with the class and method names joined through :: (for the class :NewClass and the method method — NewClass::method). This makes it possible to define class methods outside the class body by specifying the desired name in the namespace. Full-fledged OOP is not implemented in the current version (see Classes and Status).