This documentation is also published as Markdown for efficient machine reading: the whole site is indexed at /llms.txt, and every page has a clean Markdown copy at the same URL with .md appended. These are generated from the same source and cost far fewer tokens to read than this rendered HTML.

Skip to main content Skip to navigation
Language

Namespaces

A namespace is a name attached to a file. Everything the file declares belongs to it.

mew
namespace Geometry.Shapes;
  
pub type Point {
    pub field x: i32;
    pub field y: i32;
}

The declaration is the first thing in the file, before even a use, and a file declares at most one. A namespace has no body and is not itself a declaration, so several files may name the same one and all contribute to it.

A file with no namespace line contributes to the global namespace, which is where most small programs live.

Reaching a namespace without importing it

A name may be written with the namespace it lives in, one segment at a time, separated by .. That works for a function, for a type in a new expression, and for a type in an annotation.

mew
// file: geometry.mew
namespace Geometry;
  
pub type Point {
    pub field x: i32;
}
  
pub fn origin() -> Point {
    return new Point { x: 0 };
}
  
// file: main.mew
#load "geometry.mew"
  
use std;
  
let made = Geometry.origin();
let built = new Geometry.Point { x: 1 };
let held: Geometry.Point = built;
  
println($"{made.x + held.x}");

Importing a namespace that no file in the compilation declares is an error, so a typo in a use is caught at the line that wrote it.

mew
use std;
use Missing;

A written-out prefix that leads nowhere is reported against the name it failed to find rather than against the namespace.

Note

. separates namespace segments and reaches an instance member. :: reaches a static member of a type and a union case. The two are not interchangeable, and which one applies follows from what is on the left.

Importing with use

use drops the prefix for one namespace. Everything that namespace makes pub is then reachable by its own name.

mew
// file: geometry.mew
namespace Geometry;
  
pub fn area(side: i32) -> i32 {
    return side * side;
}
  
// file: main.mew
#load "geometry.mew"
  
use std;
use Geometry;
  
println($"{area(4)}");

Every use comes after the namespace declaration and before the first declaration in the file. One written later is an error.

A use is per file. Importing a namespace in one file does nothing for any other, so each file says for itself what it depends on.

Visibility

pub is the only visibility modifier, and what it means depends on what carries it.

On Without pub With pub
A type, union or interface The file that declares it Every file in the compilation
A free function The file that declares it Every file in the compilation
A field or a method The type that declares it Every file in the compilation

The first two rows are the ones that surprise people: a declaration without pub belongs to its file, which is narrower than its namespace. Two files sharing a namespace still cannot see each other's private declarations.

mew
// file: geometry.mew
namespace Geometry;
  
type Hidden {
    pub field x: i32;
}
  
// file: main.mew
#load "geometry.mew"
  
namespace Geometry;
  
let value = new Hidden { x: 1 };

Reaching something that exists but is not visible is reported as exactly that, rather than as a name that does not exist. Saying a name is missing when it is right there would send a reader hunting for a typo.

A field or method is scoped to its type rather than to its file, so pub on one opens it to everything. Interface members are public by definition, and writing pub inside an interface block is an error.

Mew is a programming language under construction.