rokdocs
v0.1

0.4. Boundary between the language and the standard libraries

This document declares the boundary between what the language defines and what the standard libraries define. This boundary is a core decision of the rok specification, and all subsequent specification documents are written on the premise of it.

0.4.1. What the language defines

The scope the language specification covers directly falls into the following five categories.

1. Logic flow

The first category is the syntax that moves values along and its meaning. It includes branches, loops, pattern matching, exception handling and labeled jumps; the syntax of async and generators, i.e. their declarator and operator keywords, also belongs to this category.

2. Container syntax

The second category is the forms for defining user types. A product type (record) groups several fields into one; a sum type (tagged) holds one of several variants. An untagged union is a device for interpreting the same memory as several types; a trait is a means of declaring a bundle of behavior; and an impl block is where concrete implementations of traits and methods go. Finally, generics enable forms that take types as parameters.

3. Meta-system

The third category is the attribute system, which attaches to the previous two categories and binds behavior. It consists of the standard attributes, a fixed set of names the language recognizes, and the template system for user-defined attributes and derive.

4. Variables / visibility / modules

The fourth category is the conventions for names and exposure. It includes the variable declaration keywords, reference modifiers, and global and constant keywords, together with visibility levels and the name-exposure conventions at module and package level.

5. Operator syntax

The last category is the shape of notations such as a + b, s[1:3], x.f and f(args).

The language does not, however, define what behavior these notations mean. A notation obtains its meaning by desugaring into trait methods registered in the standard libraries.

0.4.2. What the standard libraries define

The standard libraries are responsible for almost all meaning outside the five categories above. Specifically: numeric and character types and their operations; operator semantics such as arithmetic, comparison, logic, bitwise, indexing and ranges, all defined as trait impls in the standard libraries; the conversion matrix containing all rules for conversion between types; and collections, typified by lists, maps, sets, tuples and strings. In addition, abstractions such as iterators, streams and futures; concurrency primitives typified by atomic, mutex and channel; task, thread and parallel execution APIs; I/O, time, randomness and networking; and all error types are defined by the standard libraries.

The language does not know the names of these library elements. The compiler recognizes a specific library type only through attribute bindings of the meta-system, and those bindings are themselves written inside the standard libraries.

0.4.3. Consequences of the boundary

Syntax is the language, behavior is the library

The first consequence of this split is a division of labor between notation and meaning.

Important

The language defines every notation, but the meaning of an operation applied to values is determined by trait methods registered in the standard libraries.

NotationWhat the language decidesWhat the library decides
a + bToken sequence, precedenceWhich trait method + is, result type
s[1:3]Shape of slice notationIndexing, bounds checking, result type
x.f()Shape of method callMethod dispatch rules
let x = 1Shape of declarationType of the literal 1

Scope of language-level questions

The second consequence of this split is a criterion for classifying questions. When facing any design or implementation decision, first determine whether it is a language-level question or a library-level question.

Questions that remain at the language level are limited to the following areas. First, compiler semantics: name resolution, closure capture, visibility and error diagnostics. Second, syntax decisions: escapes, precedence, literal suffixes, the shape of slice notation, etc. Third, run-time calling conventions and the memory model, including object layout and calling convention. Fourth, resource management: lifetimes and the exception propagation mechanism. Fifth, type system rules: the trait-as-type ban, gradual typing, niche optimization, etc.

What is delegated to the library level

Operations on almost all values outside the list above are the library's decision. This specification therefore does not prescribe the semantics of such operations directly.

Instead, the specification states the following: which trait method call the operation desugars into; the location convention for which library tier defines that trait; and the form of the compile error that occurs when it is not defined.

This split is how rok's design slogan, "a small language, rich libraries", is realized at the specification level.

0.4.4. Implementation limits

The language sets no fixed limits on nesting, chain length, value size or compile-time evaluation. An implementation may set its own; they are implementation-defined, not language requirements. rok's are:

Limitrok
Parser nesting depth256
Operator / postfix chain links (3.2.6a)4096
Value type size (2.6.3)65536 flattened scalar slots or 4 GiB
const evaluation (5.2.4)4,000,000 steps, call depth 128

Exceeding one is a compile error.

Edit this page on GitHub