Skip to content

Modularity

Paul T edited this page May 23, 2017 · 1 revision

CTalk, unlike C, work under the model of modules and imports as opposed to header files and include. It is essentially a namespace with visibility and access control.

Consider the following project layout:

project/
|- main.ct
|- foo/
|  |- a.ct
|  |- b.ct
|- bar/
|  |- b.ct
|  |- baz/
|  |  |- c.ct

Modules

The file foo/a.ct should declare itself under the module of foo::a. For foo/b.ct, the module should be foo::b. Similarly, bar/b.ct should be declared as bar::b and baz/c.ct as bar::baz::c.

Of course, you can choose to omit the module declaration. This will result all its definitions to be considered HIDDEN in what is called the nameless module.

Definitions done inside a module can have these access modifiers:

  • export means definition is visible to all modules.
  • internal means definition is visible to itself and its sub-modules.
  • hidden means definition is only visible to itself.

If the access modifier is omitted, the visibility of hidden is applied.

Since modules cannot be declared in a nested form, a sub-module implies that the module starts with the same path as another module. bar::baz::c in the example above would not be a sub-module of bar::b even though they share a common path of bar.

Each file can, however, contain more than one module definition. Consider the following source file:


import std::io;

module foo

    export function f()
        std::io::println str:"foo::f()";
    end;

    internal function g()
        std::io::println str:"foo::g()";
    end;

    hidden function h()
        std::io::println str:"foo::h()";
    end;
end;

#{ To access this module, import foo instead
   of foo::Bar. #}
module foo::Bar

    #{ This module can see foo::f() and foo::g().
       foo::h() is not visible because it has a
       visibility of hidden (omit implies
       hidden). #}
    export function a()
        foo::f(); # Exported access: Valid
        foo::g(); # Internal access: Valid
        # foo::h(); # Hidden access: Error
    end;
end;

export function a()
    foo::f(); # Exported access: Valid
    # foo::g(); # Internal access: Error
    # foo::h(); # Hidden access: Error
end;

Import

Importing is similar to the #include directive in C except that it only includes the specified location once in each phase (once in the symbol generating phase, once in the code generating phase). It is necessary to write out the import line (different from java packages where the compiler will find its definition).

When importing a module, the compiler searches in this order:

  1. The CTalk standard library
  2. The directory of the current source file

Since it is impossible to change the search priority, it is strongly advised to not name modules starting with std. After a file is imported, the definitions do not pollute the current namespace. Referencing its exported entities still require the full name.

Referencing definitions inside the current module requires an underscore. For example: _::foo. Without the prefixing underscore results in a search in the nameless module.

Clone this wiki locally