Eigenstate : Myrddin Modules

The Myrddin Module System Is Very Simple

The Myrddin module system is simple and easy to understand. There simply isn't much to it. Your code is written in files. Your files export symbols into a namespace. Multiple files may export symbols into the same namespace. These files are assembled by the build system into packages. The list of files in a package is explicit in your build file.

Because the package is compiled, importing the package from within a package won't work. Since it's useful to import functions from other files in the same package, you may import files that are part of the current project directly.

The Module System Is Easy To Understand

Myrddin was designed with care to allow for separate compilation. There is no complexity from the compilation model that the system needs to deal with.

You either point the use statement at a file in your directory, or you point it at a package that has already been compiled. As a result, your source files form a directed graph of dependencies. Cycles are not allowed. The build system reads your sources and builds them in reverse topological order, starting at the leaves of the DAG and walking upwards.

The search path for the modules is simple and fairly explicit. If you explicitly want a package within the project, you use the lib clause in your build file. Otherwise, the paths given by -I are searched, followed by $prefix/lib/myr.

There Isn't Much Syntax

The module system has exactly two keywords, use and pkg.

Importing symbols is done via use packagename, where packagename is either a single keyword referencing a package (eg, use std), or a quoted string referencing a file in the project (eg, use "mysource").

Exporting symbols into packages is done via pkg foo = declarations ;;, where foo is the package namespace, and declarations is a list of symbols that should be exported. By convention, the types are manifestly declared here for readability. However, the syntax of the declaration is exactly the same as the syntax of any declaration at any other point in the file.

For example, if you had a file named hello.myr, you might write:

use std
pkg demo =
    const hello : (-> void)
;;
const hello = {; std.put("hello world!\n")}

This exports the hello function into the demo namespace. adding another file that exports a function in the namespace is trivial. For example, if this were in goodbye.myr, you might write:

use std
pkg demo =
    const goodbye   : (-> void)
;;
const goodbye = {; std.put("goodbye world!\n")}

Now, if you want a function that calls both functions above, you might create a file named "greetdepart.myr", with the following code inside:

use std
use "hello"
use "goodbye"
pkg demo =
    const hibye : (-> void)
;;
const hibye = {
    hello()
    goodbye()
}

You may notice that std is not quoted, but "hello" and "goodbye" are quoted. This is how Myrddin handles the distinction between packages and files when referencing code in the use statements.

To build this, you might put the following into your bld.proj file:

lib demo =
    hello.myr
    goodbye.myr
    greetdepart.myr
;;

At this point, you can run the following to build and install the code:

$ mbld install
project base /home/ori/x:
/libdemo.a...
    6m  hello.myr 
    6m  goodbye.myr 
    6m  greetdepart.myr 
    muse    -o libdemo.use -p demo greetdepart.use goodbye.use hello.use 
    ar  -rcs libdemo.a greetdepart.o goodbye.o hello.o 
    libdemo.use => /home/ori/bin/lib/myr/libdemo.use
    libdemo.a => /home/ori/bin/lib/myr/libdemo.a

And any future projects can use it via:

use demo
const main = {;demo.hibye()}

There Is No Namespace Graph

A package contains all the exported symbols in the namespace. Namespaces do not nest, and do not include other namespaces. And importing a namespace does not import any dependent symbols from any other namespace.

There's no need for complexity or construction of a namespace graph.

There Isn't Any More

Really. This is a full description. Some people may call it crude. Others might call it simplistic. Some might even call it a steaming pile of shit. They'd probably be right.

Thanks to Without Boats for the description of the Rust module system that inspired me to write this up.