Docs/Types

Namespaces & globals

Split code into namespaces, control visibility, and use globals and aliases.

On this page

Every directory under src is a namespace. Declarations in a namespace are reached through its name, and markers decide who else can see them.

Use a namespace#

use makes a namespace available in the current file. Standard library namespaces start with valk.:

Valk
use valk.fs
use valk.time as clock

fn main() {
    let path = fs.Path.new("docs").add("notes.txt")
    println(path)                 // docs/notes.txt
    println(clock.unix_ms() > 0)  // true
}
  • The last part of the path is the name: use valk.fs gives fs.
  • use x as name picks another name.
  • A project's own namespaces are its directories, so src/greetings/ is use greetings. See Projects & packages.

Visibility#

An unmarked declaration is available throughout its package. A marker in front of it changes that:

Marker Visible
none in this package
- in this source file only
-+ in this namespace only
+ everywhere, also to other packages
~ read-only outside this source file (properties and globals)
~+ read-only outside this namespace
Valk
+ fn public_api() String { return helper() }
fn helper() String { return "package wide" }
- fn file_only() {}

+ class Config {
    + name: String           // everyone can read and change it
    ~+ version: uint (1)     // everyone reads, only this namespace writes
    - secret: String ("")    // only this file
}

- is private to the file, not to the class: other code in the same file can still use it. Operator methods such as $eq and hash that standard containers call need +.

Globals#

A global holds one value per thread. A shared global is one value for the whole program:

Valk
global requests: uint
global greeting: String ("hello")
shared started_at: uint (42)

fn count() {
    requests++
}

fn main() {
    count()
    count()
    println(requests)    // 2
    println(greeting)    // hello
    println(started_at)  // 42
}
  • A default goes in parentheses and runs before main. Defaults may read other globals; they run in the right order.
  • Without a default a global starts at zero, so classes, strings and closures need a default.
  • A shared global is read as atomic T; see Sharing data between threads for what you can change through it.

Aliases, types and constants#

Valk
use valk.fs

alias Path for fs.Path            // another name for a declaration
type Check (fn(int)(bool))        // a name for a type expression
value PAGE_SIZE (16 * 4)          // a compile-time constant

fn main() {
    let dir: Path = "."
    let positive: Check = fn(n: int) bool { return n > 0 }
    println(positive(PAGE_SIZE))  // true
    println(PAGE_SIZE)            // 64
    println(dir)                  // .
}

Add $global after a declaration to use its name in every namespace without a prefix, for example alias Path for fs.Path $global.