Hash language modules
A module in Hash
can contain variable definitions, function definitions, type definitions or include other modules.
Each .hash
source file is a module, and inline modules can also be created using mod
blocks.
Importing
Given the project structure:
.
├── lib
│ ├── a.hash
│ ├── b.hash
│ └── sub
│ └── c.hash
└── main.hash
Modules in hash allow for a source to be split up into smaller code fragments, allowing for better source code organisation and maintenance.
You can import modules by specifying the path relative to the current path.
For example, if you wanted to include the modules a
, b
, and or c
within your main file
#![allow(unused)] fn main() { // main.hash a := import("lib/a"); b := import("lib/b"); c := import("lib/sub/c"); }
By doing so, you are placing everything that is defined within each of those modules under the namespace.
Exporting
In order to export items from a module, use the pub
keyword.
For example:
#![allow(unused)] fn main() { /// a.hash // Visible from outside: pub a := 1; // Not visible from outside (priv by default): b := 1; // Not visible from outside: priv c := 1; /// b.hash { a } := import("a.hash"); // Ok { b } := import("a.hash"); // Error: b is private { c } := import("a.hash"); // Error: c is private. }
Referencing exports
Furthermore, if the a
module contained a public structure definition like Point
:
#![allow(unused)] fn main() { // a.hash pub Point := struct( x: u32, y: u32, ); }
Within main, you can create a new Point
by doing the following
#![allow(unused)] fn main() { // main.hash a := import("lib/a"); p1 := a::Point( x = 2, y = 3, ); print(p1.x); // 2 print(p1.y); // 3 }
From this example, the ::
item access operator is used to reference any exports from the module.
Furthermore, what if you wanted to import only a specific definition within a module such as the 'Point' structure from the module a
.
You can do so by destructuring the definitions into using the syntax as follows:
#![allow(unused)] fn main() { { Point } := import("lib/a"); p1 := Point(x=2, y=3); }
In case you have a member of your current module already reserving a name, you
can rename the exported members to your liking using the as
pattern operator:
#![allow(unused)] fn main() { { Point as LibPoint } = import("lib/a"); p1 := LibPoint(x=2, y=3); }
Inline modules
Other than through .hash
files, modules can be created inline using mod
blocks:
#![allow(unused)] fn main() { // a.hash bar := 3; pub nested := mod { pub Colour := enum(Red, Green, Blue); }; // b.hash a := import("a.hash"); red := a::nested::Colour::Red; }
These follow the same conventions as .hash
files, and members need to be exported with pub
in order to be visible from the outside.
However, the external module items are always visible from within a mod
block, so in the above example, bar
can be used from within nested
.
Grammar
The grammar for file modules is as follows:
file_module = ( expr ";" )*
The grammar for mod
blocks (which are expressions) is as follows:
mod_block = "mod" "{" ( expr ";" )* "}"