-
Notifications
You must be signed in to change notification settings - Fork 0
Modularity
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
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:
-
exportmeans definition is visible to all modules. -
internalmeans definition is visible to itself and its sub-modules. -
hiddenmeans 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;
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:
- The CTalk standard library
- 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.