Currently in Beta 🌸🌸

Modules

Ghost employs a simple module system to split and organize code into self-contained files.

Every ghost file is its own module with its own scope. Importing a file into another does not explicitely merge its scope. For example, two modules can define the same top-level variable with the same name without causing any name collision.

Shared Imports

Ghost keeps track of every file it imports. Importing a module in multiple locations will not execute or load that module every time. The first encounter of the imported module will be the only time its loaded and evaluated.

Binding Variables

All top-level variables within a module are exportable. To actually import data, you may specify any number of identifiers in your import statement:

import Request, Response from "http"

The above will import and bind the values Request and Response from the http module. This will make Request and Response available in your file.

Aliases

You may import a variable under a different name using as:

import str as isString from "helpers"

Import an entire module's contents

To import every value from a module, you may use *:

import * from "helpers"

Cyclic Imports

Cyclic imports for the most part are "supported" by Ghost, though they should still be considered a code smell if you ever come across them. Because Ghost keeps track of the modules it imports, it's effectively able to short-circuit itself on cyclic imports:

// main.ghost
import "a";

// a.ghost
print("start a");
import "b";
print("end a");

// b.ghost
print("start b");
import "c";
print("end b");

// c.ghost
print("start c");
import "a";
print("end c");

When running the above program, you'll find that it prints the correct output and does not get stuck in an infinite loop:

start a
start b
start c
end c
end b
end a

Importing Side Effects

Import an entire module for side effects only, without importing anything. This runs the module's global code, but doesn't actually import any values.

import "beverages"

This will evaluate the module and run it, but it will not bind any new variables.

Introducing An Example

To demonstrate the usage of modules, we're going to show a very simple example below.

Basic Example Structure

In our example, we have the file structure below:

main.ghost
modules/
    functions.ghost
    variables.ghost

main.ghost

import * from "modules/functions"
import * from "modules/variables"

print("Program loaded.")

add(one, two)
greet(hello)

functions.ghost

function add(a, b) {
  print(a + b)
}

function greet(message) {
  print(message)
}

variables.ghost

one = 1
two = 2
hello = "Hello, world!"

While this is a very rudimentary example, it showcases how simple it is to load in modules. Modules are nothing more than other Ghost files, and can be located anywhere within your program. We chose to put our modules in a modules directory, but you don't have to do this.