Before any user code is elaborated, an environment already exists: a collection of classes and values that the Definition presupposes and every program may use. This appendix records that standard environment, \(E_0\). It is not a complete library reference—for that, see the Nex Reference—but the part of the standard environment on which the semantics of earlier chapters depends.
B.1The Root and the Foundational Classes
Every class conforms ultimately to Any, the root of the class
hierarchy and the elaborated form of the type \(\mathsf{Any}\)
(Section 4.1). A user class may write inherit Any explicitly,
but does so implicitly in any case.
| Class | Routine | Signature | Meaning |
|---|---|---|---|
Any | to_string | \(\to\) String | user-facing rendering |
equals | Any \(\to\) Boolean | value equality, used by =; overridable | |
clone | \(\to\) Any | copy; collections override with deep copy |
Four further foundational classes are present in \(E_0\):
Function—the base class of all closures, and the elaborated form of the bare type \(\mathsf{Fun}\). It supplies the invocation protocolcall0,call1, …, by which a closure of any arity up to a fixed bound is applied.Cursor—the abstract iteration interface, with routinesstart,item,next, andat_end. Theacrossloop is defined in terms of this protocol (Appendix C).Comparable(deferred)—withcompare:Any\(\to\)Integer, returning a negative, zero, or positive ordering result, the basis of the comparison operators on ordered values.Hashable(deferred)—withhash\(\to\)Integer, returning a stable hash code, on which theMapandSetclasses rely.
B.2Scalar Classes
The lexically reserved type names denote classes of the standard environment. They
are Comparable and Hashable, and support the arithmetic
and comparison through which the operators of Section 2.6 are given
meaning.
| Type | Values | Notes |
|---|---|---|
Integer | machine integers | literals of int form; default numeric type |
Integer64 | 64-bit integers | for explicit width |
Real | floating-point | literals of real form; Real / Integer yields Real |
Decimal | exact decimals | for arithmetic without rounding error |
Char | characters | literals of char form |
Boolean | true, false | operand and result of the logical operators |
String | text | literals of string form; iterates by character |
The arithmetic operators apply to numeric operands, returning the wider type
(Section 4.4); an integer operand is admitted where a real is required, so
that total / count with total of type Real
yields a Real. The comparison operators apply to
Comparable operands through compare. Scalars are
immutable and unstored, so identity equality == coincides with value
equality = upon them (Section 5.3).
B.3Scalar Value Spaces
The previous section names the scalar classes; this one fixes the
value spaces they denote—their ranges, their numeric formats, and
the character model of Char and String. The
guiding decision of the Definition here is deliberate and worth stating plainly:
the Definition fixes the abstract value space and a guaranteed minimum
for each scalar type, but leaves exact bounds, overflow behaviour, and rounding
to the host. Nex compiles to more than one platform—the Java
virtual machine and JavaScript at present—and those platforms do not agree
on the size of an integer or the realisation of an exact decimal. Rather than
impose a single width and so constrain or penalise one back end, the Definition
specifies what every conforming implementation must provide and marks the rest as
host-defined. A program that stays within the guaranteed range and does
not depend on overflow behaviour means the same thing on every platform; a
program that relies on a host-defined property means what that host says, and the
Definition assigns it no portable meaning.
Integer types
Integer is a signed two’s-complement integer of
at least 32 bits. Its exact width is host-defined: on the JVM
an Integer is carried with 64-bit range; on JavaScript it is a
double-precision number, exact for magnitudes up to \(2^{53}-1\). A program may
rely on the range \([-2^{31},\, 2^{31}-1]\) on every platform, and no more. The
result of an operation that exceeds the host range is host-defined: it may raise
an error, wrap, widen, or lose precision, so portable code must not depend on it.
The JVM back end performs checked arithmetic, raising an overflow error
rather than wrapping silently when an integer operation leaves the host range.
Integer64 is a signed two’s-complement integer of exactly
64 bits, range \([-2^{63},\, 2^{63}-1]\), on every platform; it
exists precisely so that a program needing a definite 64-bit width need not rely
on the host width of Integer.
The bitwise operations of Integer
(bitwise_left_shift and its companions) operate on the low
32 bits, with bit 0 the least significant, independently of
the host width. Whether an integer literal that does not fit the host range is
accepted is host-defined (Section 2.2).
Real and Decimal
Real is represented as an IEEE 754
double-precision binary floating-point value on every platform: a real
literal denotes the nearest representable double, which may not be the decimal
written, so that 0.1 + 0.2 evaluates to
0.30000000000000004 and not to 0.3. The
representation is thus pinned down tightly, because both hosts provide
IEEE 754 and agreement costs nothing.
The arithmetic, however, does not follow IEEE 754 in every
respect. In particular, division by zero does not yield an infinity or a
not-a-number value: 1.0 / 0.0 and 0.0 / 0.0 both
raise a division-by-zero error. Consequently the special values
\(\pm\infty\) and NaN are not produced by ordinary division, and a
program cannot rely on the IEEE behaviour of NaN (such as its being
unequal to itself) arising from arithmetic. Whether such values can be obtained
by other means, and how they then compare, is host-defined.
Decimal is an exact base-ten number, free of the
binary rounding error of Real; it is the type to use for money and
for any quantity where a written decimal must be represented faithfully. Its
realisation is host-defined: on the JVM it is an arbitrary-precision
BigDecimal, so neither magnitude nor number of fractional digits is
bounded in practice; on other hosts the available precision and the rule for
rounding an inexact result are host-defined. A program may rely on
Decimal to represent any decimal literal it writes exactly, and on
exact results for addition, subtraction, and multiplication; the precision of a
division that does not terminate, and any rounding it entails, are host-defined.
Boolean and the character model
Boolean has exactly the two values true and
false.
A Char is a single Unicode code point. A
character constant may be written as a literal character, as one of the named
characters of Section 2.2, or as a decimal code point after #,
so that #65 denotes the same character as #A. A
String is a finite sequence of characters; its length
is the number of characters, it iterates character by character
(Section 2.8), and char_at and chars address it by
character position. The encoding of a string is exposed only through
to_bytes, which yields the UTF-8 bytes of the
string as integers in the range \([0, 255]\), on every platform; the internal
representation by which a host stores a string, and the relation between a
character index and any underlying code-unit index, are host-defined and not
observable except through to_bytes. There are no escape sequences in
string literals (Section 2.2); a control character is written with its
character constant or obtained from the standard environment.
| Type | Guaranteed by the Definition | Host-defined |
|---|---|---|
Integer | signed, ≥ 32 bits; range \([-2^{31}, 2^{31}-1]\) portable; bitwise on low 32 bits | exact width; out-of-range and overflow behaviour |
Integer64 | signed 64-bit, range \([-2^{63}, 2^{63}-1]\) | — |
Real | IEEE 754 double representation; literal rounds to nearest double | division by zero raises; availability and comparison of \(\pm\infty\) / NaN |
Decimal | exact base-ten; literals and +, −, × exact | precision bound; rounding of non-terminating division |
Char | a Unicode code point | internal representation |
String | sequence of characters; length in characters; to_bytes is UTF-8 in \([0,255]\) | internal encoding; character-to-code-unit mapping |
B.4Collection Classes
Three generic collection classes are present in \(E_0\), each a
Cursor source so that across may traverse it.
Array[T]
An ordered, growable sequence. The display [e₁, …, eₙ] is a
derived form constructing an Array (Appendix C). Representative
routines: get(i) \(\to\) T, add(x) to
append, length \(\to\) Integer.
Map[K, V]
An association of keys to values. The display
{k₁: v₁, …} is a derived form; {} is the empty map.
Representative routines: get(k) \(\to\) V,
put(k, v), iteration yielding [key, value] pairs.
Set[T]
An unordered collection of distinct values. The display
#{e₁, …} is a derived form; #{} is the empty set, which
must be written with the explicit set-display syntax to distinguish it from the
empty map. The constructor from_array builds a set from an array,
discarding duplicates; the routines union, intersection,
difference, contains, and size provide the
usual set algebra.
B.5Concurrency Classes
The classes underlying Chapter 6 are part of the standard environment.
| Class | Routine | Meaning |
|---|---|---|
Task[T] | await | block until done; yield result of type T |
await(ms) | timed await; nil on timeout | |
is_done, is_cancelled | completion and cancellation state | |
cancel | request cancellation | |
await_any, await_all | (class methods) wait on a collection of tasks | |
Channel[T] | send(v), receive | blocking communication (Section 6.2) |
try_send, try_receive | non-blocking variants used by select | |
with_capacity(n) | (constructor) a buffered channel | |
close, is_closed, size, capacity | channel state |
A spawn whose block assigns result of type \(T\)
yields a Task[T]; one that does not yields a plain
Task.
B.6Built-in Values and Effects
A handful of values are bound in the top-level bindings of \(E_0\). Chief
among them is print, which renders its argument (via
to_string) and writes it to the standard output—a host effect,
and the principal observable behaviour of many programs. The Console
class provides finer output control, including new_line; because
string literals do not interpret escapes (Section 2.2), a line break in
output is produced with Console.new_line or the character constant
#newline rather than with a backslash escape.
The exception values raised by the language itself—on a nil
dereference, a failed contract, a failed runtime argument check, an out-of-range
collection access—are also part of the environment, and are the values a
rescue block receives in exception (Section 5.7).