<- ^ ->
Module system

18   Module system

Modules provide way of separate compilation along with possibility of avoiding namespace conflicts. Current module system is based on ideas from OCaml. However, compared to OCaml, it is very limited, we only support one level of modules, there are no functors and so on.

18.1   Interface

Interface part of module Foo goes to file foo.gi. This is similar to .h header in C. It contains function prototypes, types definitions, variables declarations and similar stuff.

The main purpose of interface file is to hide implementation details.

Hiding information about defined functions and variables is easy -- you simply do not provide prototype or declaration, and no one, outside foo.g, will be able to call this function, or reference variable.

You can also hide information about types, by writing type bar in foo.gi, you say: ``I will define type named bar in foo.g, but users of this module doesn't need to know what exactly this type is''. Of course if there is no need to even say, that bar is defined, you can omit type bar, and just define it in foo.g.

It is also possible to disclosure types in interface. It is done exactly the same way as in implementation file.

Now some example:

// interface of Foo

// reset module to initial state
void reset();

// don't disclosure actual type of file
type file;

// but provide definition for type used as interface
union open_flag {
        void Open_rdonly;
        void Open_rdwr;
        void Open_wronly;
        int Open_to_append;     // int argument specifies at which point
                                // to start appending (I know it's 
                                // stupid :-)
}

file open(open_flag flag);

// global variable
int open_files_cnt;

18.2   Implementation

Implementation part of module Foo goes to file foo.g. Actual function, variable and type definitions are here.

All symbols defined in Foo are prefixed with Foo::. This allows having function (or type, or variable) named foo in both Bar and Baz modules.

Now we might look at some more realistic example:

File mylist.gi:

        // this is to output information,
        // that we implement type `t', but not to
        // disclosure what it is.
        type <'a>t;

        // return first element (head) of the list
        'a hd(<'a>t x);
        
        // return all but first element (tail) of the list
        <'a>t tl(<'a>t x);

        // create new empty list
        <'a>t create();
        
        // apply f to all elements of l, return list of results
        <'b>t map(*('b ('a)) f, <'a>t l);

        // call f on all elements of the list
        void iter(*(void ('a)) f, <'a>t l);
File mylist.g:

        // this is local datatype.
        opt_struct <'a>t {
                'a data;
                <'a>opt_struct next;
        }
        
        // this will be exported out (`public')
        'a hd(<'a>t x) { return x.data; }
        <'a>t tl(<'a>t x) { return x.next; }
        
        // this is local, can't be called from outside the module
        void helper(<'a>t x) { ... }

        // and more publics
        <'a>t create() { return null; }
        // we already wrote these
        <'b>t map(*('b ('a)) f, <'a>t l) { ... }
        void iter(*(void ('a)) f, <'a>t l) { ... }
        // ...
Then if you want to use the module, it can be done with :: notation, like this:

        <int>Mylist::t l = Mylist::create();
        ...
        int k = Mylist::hd(l);
In case of some modules it might be useful to open them, i.e. import all symbols from module into current namespace, so you no longer have to use :: notation (but you still can, it is often suggested for readability):

        open Mylist;
        ...
        <int>Mylist::t l = Mylist::create();
        ...
        int k = hd(l);
        // it might be hard to tell what <int>t refers to here,
        // so using Mylist::t is recommended
        <int>t rest = tl(l);

18.3   Hey, where did #include go?

In Gont, at present, there is no #include. Also you cannot prototype functions from other modules in implementation files. Modules are more abstract, higher level mechanism, that should be used instead. It is much harder to make a mistake when using modules, and it's not all that hard, once you used to them.

#include (and #define for that matter) might be implemented in some unspecified future, if there are some good reasons to. However #include won't be used for modularization.

18.4   Std module

Std module is open at the beginning of each compilation unit. It includes few primitive functions, exceptions and types.

<- ^ ->
Module system