rokdocs
v0.1

5.7. Paths

A sequence of identifiers joined by the :: token (punctuation and operator tokens) is a path that designates a location in the module tree. This document defines paths as references to modules and items.

Type paths covers paths in type position; this document covers paths referring to values and modules. Both have the same form.

path            ::= path_root ("::" path_segment)*
path_root       ::= "pkg" | "sup" | "rok" | identifier
path_segment    ::= identifier
                  | identifier "::" "<" type_arg_list ">"      // turbofish
type_arg_list   ::= type_expr ("," type_expr)* ","?

The grammar above defines only the turbofish (name::<T>) of value and module position paths. Generics written as name<T> in type position are defined by type_path in type paths.

5.7.1. Starting identifier of a path

The first identifier of a path is one of:

Start tokenMeaning
pkgFrom the root of the current package
supFrom the parent module
rokThe standard library virtual namespace
Ordinary identifierA currently visible name (child module, used name)

pkg shares its stem with the visibility keyword pub(pkg), and sup is the mirror direction of the visibility pub(sub) (sub means descendants, sup means ancestors). rok is a virtual root that groups the compiler-managed standard library packages under one name. All three are path roots only when immediately followed by ::; elsewhere they are ordinary names (1.5.4 Contextual keywords).

self:: is not a path starting point. Children and items of the same module are reachable by ordinary identifiers (child::item).

Name resolution does not implicitly search ancestor modules (exception: extern functions, 5.9.4). An ordinary identifier is looked up only among the current module's items, child modules, and names imported with use (including the implicit use rok::core::**). Items of the parent or higher modules must be named with sup:: or imported with use.

Lookup order is as follows; the first match wins.

  1. Items and child modules of the current module
  2. uses of the current module. Named imports take precedence over globs (*, **).
  3. The implicit use rok::core::**

Functions, generic or not, share a single value name space. The nearest declaration therefore wins regardless of kind (a non-generic max in the current module hides the generic max of core).

// inside pkg::a::b
helper();              // ERROR - no implicit search even if helper is in pkg::a
sup::helper();         // OK

5.7.2. pkg::: from the package root

pkg::geom::Point
pkg::config::DEFAULT_TIMEOUT
pkg::main_module::run

pkg:: starts from the package's root module (src/main.rok or src/lib.rok) and is written the same way anywhere in the package. It is the standard form for safe absolute references in large codebases.

5.7.3. sup::: from the parent module

sup::sibling_function
sup::parent_const

sup:: starts from the current module's parent module, so it suits references to items of sibling and parent modules. To go up several levels, chain it as sup::sup::....

sup::sup::ancestor_item

5.7.4. rok::: the standard library virtual namespace

rok::core::vec::Vec
rok::core::iter::Iterator
rok::bare::ptr::Ptr
rok::std::fs::File

rok:: designates the compiler-managed set of standard library packages. Under it, three tiers exist as separate packages (0.5 Standard library tiers).

PathMeaningLink mechanism
rok::bare::*raw / unsafe area-NL bare
rok::core::*foundation / commonly used traits-NL core
rok::std::*OS integration / I/O etc.-NL std

The three packages are separate archives the compiler links automatically at build time, handled by the -NL mechanism distinct from user package dependencies. In source, rok merely presents them under one path root; the build system separates the package boundaries.

rok::bare and rok::std are not automatically imported and require an explicit import. The rok::core area, by contrast, is visible automatically through the implicit use rok::core::**; defined in 5.5 use.

5.7.5. Starting with an ordinary identifier

foo::bar::baz                   // OK if foo is a currently visible name
geom::Point                      // if the geom module is a child or imported
Point                            // just a single name - resolved automatically

If the first identifier is a name visible in the current module, it can be used as is. A visible name here means a child module or an item imported with use.

5.7.6. Meaning of each path segment

pkg::geom::shapes::Circle
└──┘  └──┘  └────┘   └────┘
root  mod   module   item

Each segment is a module or (for the last one) an item. The last identifier is the final item being designated; the preceding segments are modules or types along the path.

5.7.7. Paths by item kind

DesignatesForm
Functionpath::function_name
Type (struct / enum / union / trait)path::TypeName
constpath::CONST_NAME
staticpath::STATIC_NAME
Module itselfpath::module_name
Static methodType::method_name
Associated constType::CONST
Associated typeT::AssocType

These are the same as the associated item access forms of type paths.

5.7.8. Expression position and type position

The same path form can be used both in expression position (designating a value) and in type position (designating a type).

// expression position
let f = pkg::geom::distance;          // function value
let p = pkg::geom::Point::origin();   // static method call
let v = pkg::config::DEFAULT;           // const value

// type position
let p: pkg::geom::Point = ...;
fn make() -> pkg::geom::Point { ... }

The difference between the two positions is whether generic arguments are written with the turbofish (::<...>). Expression position uses the turbofish; type position uses plain <...>. Details are in type paths.

5.7.9. Combining paths and globs

Combined with the import forms of use, various import notations are available.

use pkg::geom::{Point, Circle, distance};
use sup::{a, b as alias};
use foo::*;

* (glob) and ** (recursive glob) behave as defined in use (imports).

5.7.10. Empty paths / a lone ::

An empty path (only :: with no identifier) is a compile error.

A leading ::, as in ::A, is also an ERROR. Absolute paths are written explicitly as pkg::A.

5.7.11. Shortening with use

A name imported with use can be used by its short name in the current module.

use pkg::geom::Point;

fn f() {
    let p = Point { ... };          // short name
    let q: Point = ...;
}

Gathering frequently used items with use at the top of a module keeps code bodies concise.

5.7.12. When paths are resolved

Path resolution happens in the compile-time name resolution phase and has no effect on runtime behavior (method dispatch on dynamic slots, however, happens separately at runtime; see any slot).

5.7.13. Referring to modules dynamically (none)

let m = "foo";
m::bar();                            // ERROR - no dynamic module references

The module part of a path is always static and determined at compile time. Receiving a module as a variable at runtime and calling functions in it is not provided.

This is consistent with the principle in modules that the module tree is a static structure.

5.7.14. Paths between packages

Items of another package (a dependency) are referenced by paths starting with that package's name.

use parser::Token;
let t = parser::lex(src);
  • The name of a dependency package is a top-level path. The name is the deps key in rok.rokon with - replaced by _ (rok-syntax → rok_syntax::..), and the build tool registers it with rokc --extern name=.. (9.2.3, 9.10.3). No separate declaration such as Rust's extern crate is needed.
  • pkg:: inside a dependency package is that dependency's own root.
  • A module of the user package with the same name as a dependency package is an error.
  • A dependency that resolves to the package being built is an error; a package names its own items with pkg::.

Package boundaries

Each of the following is a separate package. The visibilities pub(pkg) / pub(sub) (5.6) do not cross these boundaries.

  • The package being built
  • Each dependency package
  • Each tier of rok:: (rok::bare, rok::core, rok::std)

Thus private / pub(sub) / pub(pkg) items of a dependency cannot be used from outside it; only pub items can.

Edit this page on GitHub