Modify manual to reflect new box/local terminology and new slot/type roles for box and mutable.
This commit is contained in:
parent
6a0b06e562
commit
aa614d5280
490
doc/rust.texi
490
doc/rust.texi
@ -223,6 +223,67 @@ Unlike many languages, individual modules do @emph{not} carry all the
|
||||
mechanisms or restrictions of crates. Modules and crates serve different
|
||||
roles.
|
||||
|
||||
@sp 1
|
||||
@item Static control over memory allocation, packing and aliasing.
|
||||
|
||||
Many values in Rust are allocated @emph{within} their containing stack-frame
|
||||
or parent strucure. Numbers, records, tuples and tags are all allocated this
|
||||
way. To allocate such values in the heap, they must be explicitly
|
||||
@emph{boxed}. A @dfn{box} is a pointer to a heap allocation that holds another
|
||||
value, its @emph{content}. If the content of a box is a @emph{state} value --
|
||||
the sort that may contain mutable members -- then the heap allocation is also
|
||||
subject to garbage collection.
|
||||
|
||||
Boxing and unboxing in Rust is explicit, though in many cases (arithmetic
|
||||
operations, name-component dereferencing) Rust will automatically ``reach
|
||||
through'' the box to access its content. Box values can be passed and assigned
|
||||
independently, like pointers in C; the difference is that in Rust they always
|
||||
point to live contents, and are not subject to pointer arithmetic.
|
||||
|
||||
In addition to boxes, Rust supports a kind of pass-by-reference slot called an
|
||||
alias. Forming or releasing an alias does not perform reference-count
|
||||
operations; aliases can only be formed on referents that will provably outlive
|
||||
the alias, and are therefore only used for passing arguments to
|
||||
functions. Aliases are not ``general values'', in the sense that they cannot
|
||||
be independently manipulated. They are more like C++ references, except that
|
||||
like boxes, aliases are safe: they always point to live values.
|
||||
|
||||
In addition, each slot (stack-local allocation or alias) has a static
|
||||
initialization state that is calculated by the typestate system. This permits
|
||||
late initialization of slotsx in functions with complex control-flow, while
|
||||
still guaranteeing that every use of a slot occurs after it has been
|
||||
initialized.
|
||||
|
||||
@sp 1
|
||||
@item Static control over mutability.
|
||||
|
||||
Types in Rust are classified as either immutable or mutable. By default,
|
||||
all types are immutable.
|
||||
|
||||
If a type is declared as @code{mutable}, then the type is a @code{state} type
|
||||
and must be declared as such. Any type directly marked as @code{mutable}
|
||||
@emph{or indirectly containing} a state type is also a state type.
|
||||
|
||||
This classification of data types in Rust interacts with the memory allocation
|
||||
and transmission rules. In particular:
|
||||
|
||||
@itemize
|
||||
@item Only immutable (non-state) values can be sent over channels.
|
||||
@item Only immutable (non-state) objects can have destructor functions.
|
||||
@end itemize
|
||||
|
||||
Boxed state values are subject to local (per-task) garbage-collection. Garbage
|
||||
collection costs are therefore also task-local and do not interrupt or suspend
|
||||
other tasks.
|
||||
|
||||
Boxed immutable values are reference-counted and have a deterministic
|
||||
destruction order: top-down, immediately upon release of the last live
|
||||
reference.
|
||||
|
||||
State values can refer to immutable values, but not vice-versa. Rust therefore
|
||||
encourages the programmer to write in a style that consists primarily of
|
||||
immutable types, but also permits limited, local (per-task) mutability.
|
||||
|
||||
@sp 1
|
||||
@item Stack-based iterators
|
||||
|
||||
@ -284,9 +345,9 @@ destructors.
|
||||
@sp 1
|
||||
@item Dynamic type
|
||||
|
||||
Rust includes support for slots of a top type, @code{any}, that can hold any
|
||||
type of value whatsoever. An @code{any} slot is a pair of a type code and an
|
||||
exterior value of that type. Injection into an @code{any} and projection by
|
||||
Rust includes support for values of a top type, @code{any}, that can hold any
|
||||
type of value whatsoever. An @code{any} value is a pair of a type code and a
|
||||
boxed value of that type. Injection into an @code{any} and projection by
|
||||
type-case-selection is integrated into the language.
|
||||
|
||||
@sp 1
|
||||
@ -331,100 +392,41 @@ and/or objects are otherwise freed from data structures holding them. The same
|
||||
destructors are run in the same order whether the object is deleted by
|
||||
unwinding during failure or normal execution.
|
||||
|
||||
Similarly, the rules for freeing immutable memory are deterministic and
|
||||
predictable: on scope-exit or structure-release, interior slots are released
|
||||
immediately, exterior slots have their reference count decreased and are
|
||||
released if the count drops to zero. Alias slots are not affected by scope
|
||||
exit.
|
||||
Similarly, the rules for freeing immutable values are deterministic and
|
||||
predictable: on scope-exit or structure-release, local slots are released
|
||||
immediately. Referenced boxes have their reference count decreased and are
|
||||
released if the count drops to zero. Aliases are silently forgotten.
|
||||
|
||||
Mutable memory is local to a task, and is subject to per-task garbage
|
||||
collection. As a result, unreferenced mutable memory is not necessarily freed
|
||||
immediately; if it is acyclic it is freed when the last reference to it drops,
|
||||
but if it is part of a reference cycle it will be freed when the GC collects
|
||||
it (or when the owning task terminates, at the latest).
|
||||
State values are local to a task, and are subject to per-task garbage
|
||||
collection. As a result, unreferenced state boxes are not necessarily freed
|
||||
immediately; if an unreferenced state box is part of an acyclic graph, it is
|
||||
freed when the last reference to it drops, but if it is part of a reference
|
||||
cycle it will be freed when the GC collects it (or when the owning task
|
||||
terminates, at the latest).
|
||||
|
||||
Mutable memory can point to immutable memory but not vice-versa. Doing so
|
||||
merely delays (to an undefined future time) the moment when the deterministic,
|
||||
top-down destruction sequence for the referenced immutable memory
|
||||
@emph{starts}. In other words, the immutable ``leaves'' of a mutable structure
|
||||
are released in a locally-predictable order, even if the ``interior'' of the
|
||||
mutable structure is released in an unpredictable order.
|
||||
State values can point to immutable values but not vice-versa. Doing so merely
|
||||
delays (to an undefined future time) the moment when the deterministic,
|
||||
top-down destruction sequence for the referenced immutable values
|
||||
@emph{start}. In other words, the immutable ``leaves'' of a state value are
|
||||
released in a locally-predictable order, even if the ``interior'' of the state
|
||||
value is released in an unpredictable order.
|
||||
|
||||
@sp 1
|
||||
@item Typestate system
|
||||
|
||||
Every storage slot in Rust participates in not only a conventional structural
|
||||
static type system, describing the interpretation of memory in the slot, but
|
||||
also a @emph{typestate} system. The static typestates of a program describe
|
||||
the set of @emph{pure, dynamic predicates} that provably hold over some set of
|
||||
slots, at each point in the program's control flow graph. The static
|
||||
calculation of the typestates of a program is a dataflow problem, and handles
|
||||
user-defined predicates in a similar fashion to the way the type system
|
||||
permits user-defined types.
|
||||
Every storage slot in a Rust frame participates in not only a conventional
|
||||
structural static type system, describing the interpretation of memory in the
|
||||
slot, but also a @emph{typestate} system. The static typestates of a program
|
||||
describe the set of @emph{pure, dynamic predicates} that provably hold over
|
||||
some set of slots, at each point in the program's control flow graph within
|
||||
each frame. The static calculation of the typestates of a program is a
|
||||
function-local dataflow problem, and handles user-defined predicates in a
|
||||
similar fashion to the way the type system permits user-defined types.
|
||||
|
||||
A short way of thinking of this is: types statically model the kinds of values
|
||||
held in slots, typestates statically model @emph{assertions that hold} before
|
||||
and after statements.
|
||||
|
||||
@sp 1
|
||||
@item Static control over memory allocation, packing and aliasing.
|
||||
|
||||
Every variable or field in Rust is a combination of a type, a mutability flag
|
||||
and a @emph{mode}; this combination is called a @emph{slot}. There are 3 kinds
|
||||
of @dfn{slot mode}, denoting 3 ways of referring to a value:
|
||||
|
||||
@itemize
|
||||
@item ``interior'' (slot contains value)
|
||||
@item ``exterior'', (slot points to to managed heap allocation)
|
||||
@item ``alias'', (slot points directly to provably-live address)
|
||||
@end itemize
|
||||
|
||||
Interior slots declared as variables in a function are allocated very quickly
|
||||
on the stack, as part of a local activation frame, as in C or C++. Alias slots
|
||||
permit efficient by-reference parameter passing without adjusting heap
|
||||
reference counts or interacting with garbage collection, as alias lifetimes
|
||||
are statically guaranteed to outlive callee lifetimes.
|
||||
|
||||
Copying data between slots of different modes may cause either a simple
|
||||
address assignment or reference-count adjustment, or may cause a value to be
|
||||
``transplanted'': copied by value from the interior of one memory structure to
|
||||
another, or between stack and heap. Transplanting, when necessary, is
|
||||
predictable and automatic, as part of the definition of the copy operator
|
||||
(@code{=}).
|
||||
|
||||
In addition, slots have a static initialization state that is calculated by
|
||||
the typestate system. This permits late initialization of variables in
|
||||
functions with complex control-flow, while still guaranteeing that every use
|
||||
of a slot occurs after it has been initialized.
|
||||
|
||||
@sp 1
|
||||
@item Static control over mutability.
|
||||
|
||||
Slots in Rust are classified as either immutable or mutable. By default,
|
||||
all slots are immutable.
|
||||
|
||||
If a slot within a type is declared as @code{mutable}, the type is a
|
||||
@code{state} type and must be declared as such.
|
||||
|
||||
This classification of data types in Rust interacts with the memory allocation
|
||||
and transmission rules. In particular:
|
||||
|
||||
@itemize
|
||||
@item Only immutable (non-state) values can be sent over channels.
|
||||
@item Only immutable (non-state) objects can have destructor functions.
|
||||
@end itemize
|
||||
|
||||
State values are subject to local (per-task) garbage-collection. Garbage
|
||||
collection costs are therefore also task-local and do not interrupt or suspend
|
||||
other tasks.
|
||||
|
||||
Immutable values are reference-counted and have a deterministic destruction
|
||||
order: top-down, immediately upon release of the last live reference.
|
||||
|
||||
State values can refer to immutable values, but not vice-versa. Rust therefore
|
||||
encourages the programmer to write in a style that consists primarily of
|
||||
immutable types, but also permits limited, local (per-task) mutability.
|
||||
|
||||
@end itemize
|
||||
|
||||
|
||||
@ -817,9 +819,10 @@ Paths fall into two important categories: @emph{names} and
|
||||
A @dfn{name} denotes an item, and is statically resolved to its
|
||||
referent at compile time.
|
||||
|
||||
An @dfn{lval} denotes a slot, and is statically resolved to a sequence of
|
||||
memory operations and primitive (arithmetic) expressions required to load or
|
||||
store to the slot at compile time.
|
||||
An @dfn{lval} denotes a slot or some component of a value held within a slot,
|
||||
and is statically resolved at compile time to a sequence of memory operations
|
||||
and primitive (arithmetic) expressions that will be executed to load or store
|
||||
the associated value, starting from the task stack frame, at run time.
|
||||
|
||||
In some contexts, the Rust grammar accepts a general @emph{path}, but a
|
||||
subsequent syntactic restriction requires the path to be an lval or a name. In
|
||||
@ -1039,13 +1042,14 @@ A Rust task's memory consists of a static set of @emph{items}, a set of tasks
|
||||
each with its own @emph{stack}, and a @emph{heap}. Immutable portions of the
|
||||
heap may be shared between tasks, mutable portions may not.
|
||||
|
||||
Allocations in the stack and the heap consist of @emph{slots}.
|
||||
Allocations in the stack consist of @emph{slots}, and allocations in the heap
|
||||
consist of @emph{boxes}.
|
||||
|
||||
@menu
|
||||
* Ref.Mem.Alloc:: Memory allocation model.
|
||||
* Ref.Mem.Own:: Memory ownership model.
|
||||
* Ref.Mem.Slot:: Memory containment and reference model.
|
||||
* Ref.Mem.Init:: Initialization state of memory.
|
||||
* Ref.Mem.Slot:: Stack memory model.
|
||||
* Ref.Mem.Box:: Heap memory model.
|
||||
* Ref.Mem.Acct:: Memory accounting model.
|
||||
@end menu
|
||||
|
||||
@ -1063,21 +1067,23 @@ A task's @dfn{stack} consists of activation frames automatically allocated on
|
||||
entry to each function as the task executes. A stack allocation is reclaimed
|
||||
when control leaves the frame containing it.
|
||||
|
||||
The @dfn{heap} is a general term that describes two separate sets of exterior
|
||||
allocations: @emph{local heap} allocations and the @emph{shared heap}
|
||||
allocations.
|
||||
The @dfn{heap} is a general term that describes two separate sets of boxes:
|
||||
@emph{task-local} state boxes and the @emph{shared} immutable boxes.
|
||||
|
||||
Exterior allocations of mutable types are @dfn{local heap} allocations,
|
||||
owned by the task. Such @dfn{local allocations} cannot pass over channels and
|
||||
do not outlive the task that owns them. When unreferenced, they are collected
|
||||
using a general (cycle-aware) garbage-collector local to each task. Garbage
|
||||
collection within a local heap does not interrupt execution of other tasks.
|
||||
State boxes are @dfn{task-local}, owned by the task. Like any other state
|
||||
value, they cannot pass over channels. State boxes do not outlive the task
|
||||
that owns them. When unreferenced, they are collected using a general
|
||||
(cycle-aware) garbage-collector local to each task. Garbage collection within
|
||||
a local heap does not interrupt execution of other tasks.
|
||||
|
||||
Exterior allocations of immutable types are @dfn{shared heap} allocations,
|
||||
and can be multiply-referenced by many different tasks. Such @dfn{shared
|
||||
allocations} can pass over channels, and live as long as the last task
|
||||
referencing them. When unreferenced, they are collected immediately using
|
||||
reference-counting.
|
||||
Immutable boxes are @dfn{shared}, and can be multiply-referenced by many
|
||||
different tasks. Like any other immutable type, they can pass over channels,
|
||||
and live as long as the last task referencing them within a given domain. When
|
||||
unreferenced, they are destroyed immediately (due to reference-counting) and
|
||||
returned to the heap memory allocator. Destruction of an immutable box also
|
||||
executes within the context of task that drops the last reference to a shared
|
||||
heap allocation, so executing a long-running destructor does not interrupt
|
||||
execution of other tasks.
|
||||
|
||||
|
||||
|
||||
@ -1086,72 +1092,57 @@ reference-counting.
|
||||
@subsection Ref.Mem.Own
|
||||
@c * Ref.Mem.Own:: Memory ownership model.
|
||||
|
||||
A task @emph{owns} all the interior allocations in its stack and @emph{local}
|
||||
exterior allocations. A task @emph{shares} ownership of @emph{shared} exterior
|
||||
allocations. A task does not own any items.
|
||||
A task @emph{owns} all the @emph{stack-local} slot allocations in its stack
|
||||
and @emph{task-local} boxes accessible from its stack. A task @emph{shares}
|
||||
ownership of @emph{shared} boxes accessible from its stack. A task does not
|
||||
own any items.
|
||||
|
||||
@dfn{Ownership} of an allocation means that the owning task is the only task
|
||||
that can access the allocation.
|
||||
|
||||
@dfn{Sharing} of an allocation means that the same allocation may be
|
||||
concurrently referenced by multiple tasks. The only shared allocations are
|
||||
those that are immutable.
|
||||
concurrently read by multiple tasks. The only shared allocations are those
|
||||
that are immutable.
|
||||
|
||||
When a stack frame is exited, its interior allocations are all released, and
|
||||
its references to heap allocations (both shared and owned) are dropped.
|
||||
When a stack frame is exited, its local allocations are all released, and its
|
||||
references to boxes (both shared and owned) are dropped.
|
||||
|
||||
When a task finishes, its stack is necessarily empty. The task's interior
|
||||
slots are released as the task itself is released, and its references to heap
|
||||
allocations are dropped.
|
||||
When a task finishes, its stack is necessarily empty and it therefore has no
|
||||
references to any boxes.
|
||||
|
||||
@page
|
||||
@node Ref.Mem.Slot
|
||||
@subsection Ref.Mem.Slot
|
||||
@c * Ref.Mem.Slot:: Memory containment and reference model.
|
||||
@c * Ref.Mem.Slot:: Stack memory model.
|
||||
|
||||
A @dfn{slot} is a component of an allocation. A slot either holds a value or
|
||||
the address of another allocation. Every slot has one of three possible
|
||||
@emph{modes}.
|
||||
A task's stack contains slots.
|
||||
|
||||
The possible @dfn{modes} of a slot are:
|
||||
A @dfn{slot} is a component of a stack frame. A slot is either @emph{local} or
|
||||
an @emph{alias}.
|
||||
|
||||
@itemize
|
||||
@sp 1
|
||||
@item @dfn{Interior mode}
|
||||
A @dfn{local} slot (or @emph{stack-local} allocation) holds a value directly,
|
||||
allocated within the stack's memory. The value is a part of the stack frame.
|
||||
|
||||
The slot holds the value of the slot.
|
||||
An @dfn{alias} references a value outside the frame. An alias may refer to a
|
||||
value allocated in another frame @emph{or} a boxed valaue in the heap. The
|
||||
alias-formation rules ensure that the referent of an alias will outlive the
|
||||
alias.
|
||||
|
||||
@sp 1
|
||||
@item @dfn{Exterior mode}
|
||||
Local slots are always implicitly mutable.
|
||||
|
||||
The slot holds the address of a heap allocation that holds the value of the
|
||||
slot.
|
||||
Local slots are not initialized when allocated; the entire frame worth of
|
||||
local slots are allocated at once, on frame-entry, in an uninitialized
|
||||
state. Subsequent statements within a function may or may not initialize the
|
||||
local slots. Local slots can only be used after they have been initialized;
|
||||
this condition is guaranteed by the typestate system.
|
||||
|
||||
Exterior slots are indicated by the @emph{at} sigil @code{@@}.
|
||||
|
||||
For example, the following code allocates an exterior record, copies it by
|
||||
counted-reference to a second exterior slot, then modifies the record through
|
||||
the second exterior slot that points to the same exterior allocation.
|
||||
@example
|
||||
type point3d = rec(int x, int y, int z);
|
||||
let @@point3d pt1 = rec(x=1, y=2, z=3);
|
||||
let @@point3d pt2 = pt1;
|
||||
pt2.z = 4;
|
||||
@end example
|
||||
|
||||
@sp 1
|
||||
@item @dfn{Alias mode}
|
||||
|
||||
The slot holds the address of a value. The referenced value may reside within
|
||||
a stack allocation @emph{or} a heap allocation.
|
||||
|
||||
Alias slots can @emph{only} be declared as members of a function or iterator
|
||||
signature, bound to the lifetime of a stack frame. Alias slots cannot be
|
||||
declared as members of general data types.
|
||||
Aliases can @emph{only} be declared as arguments in a function or iterator
|
||||
signature, bound to the lifetime of a stack frame. Aliases are not general
|
||||
values and cannot be held in boxed allocations or other general data types.
|
||||
|
||||
Alias slots are indicated by the @emph{ampersand} sigil @code{&}.
|
||||
|
||||
The following example function accepts a single read-only alias parameter:
|
||||
An example function that accepts an alias parameter:
|
||||
@example
|
||||
type point3d = rec(int x, int y, int z);
|
||||
|
||||
@ -1160,28 +1151,68 @@ fn extract_z(&point3d p) -> int @{
|
||||
@}
|
||||
@end example
|
||||
|
||||
The following example function accepts a single mutable alias
|
||||
parameter:
|
||||
An example function that accepts an alias to a mutable value:
|
||||
@example
|
||||
fn incr(mutable &int i) @{
|
||||
fn incr(& mutable int i) @{
|
||||
i = i + 1;
|
||||
@}
|
||||
@end example
|
||||
|
||||
@page
|
||||
@node Ref.Mem.Box
|
||||
@subsection Ref.Mem.Box
|
||||
@c * Ref.Mem.Box:: Heap memory model.
|
||||
|
||||
A @dfn{box} is a reference to a reference-counted heap allocation holding
|
||||
another value.
|
||||
|
||||
Box types and values are constructed by the @emph{at} sigil @code{@@}.
|
||||
|
||||
An example of constructing a box type and value:
|
||||
@example
|
||||
let @@int x = @@10;
|
||||
@end example
|
||||
|
||||
Some operations implicitly dereference boxes. Examples of such @dfn{implicit
|
||||
dereference} operations are:
|
||||
@itemize
|
||||
@item arithmetic operators (@code{x + y - z})
|
||||
@item name-component selection (@code{x.y.z})
|
||||
@end itemize
|
||||
|
||||
@page
|
||||
@node Ref.Mem.Init
|
||||
@subsection Ref.Mem.Init
|
||||
@c * Ref.Mem.Init:: Initialization state of memory.
|
||||
An example of an implicit-dereference operation performed on box values:
|
||||
@example
|
||||
let @@int x = @@10;
|
||||
let @@int y = @@12;
|
||||
check (x + y == 22);
|
||||
@end example
|
||||
|
||||
Other operations act on box values as single-word-sized address values,
|
||||
automatically adjusting reference counts on the associated heap
|
||||
allocation. For these operations, to access the value held in the box requires
|
||||
an explicit dereference of the box value. Explicitly dereferencing a box is
|
||||
indicated with the @emph{star} sigil @code{*}. Examples of such @dfn{explicit
|
||||
dererence} operations are:
|
||||
@itemize
|
||||
@item copying box values (@code{x = y})
|
||||
@item passing box values to functions (@code{f(x,y)})
|
||||
@end itemize
|
||||
|
||||
An example of an explicit-dereference operation performed on box values:
|
||||
@example
|
||||
fn takes_boxed(@@int b) @{
|
||||
@}
|
||||
|
||||
fn takes_unboxed(int b) @{
|
||||
@}
|
||||
|
||||
fn main() @{
|
||||
let @@int x = @@10;
|
||||
takes_boxed(x);
|
||||
takes_unboxed(*x);
|
||||
@}
|
||||
@end example
|
||||
|
||||
A slot is either initialized or uninitialized at every point in a program. An
|
||||
@dfn{initialized} slot is one that holds a value. An @dfn{uninitialized} slot
|
||||
is one that has not yet had a value written into it, or has had its value
|
||||
deleted, and so holds undefined memory. The typestate system ensures that an
|
||||
uninitialized slot cannot be read, but can be written to. A slot becomes
|
||||
initialized in any statement that writes to it, and remains initialized until
|
||||
explicitly destroyed or until its enclosing allocation is destroyed.
|
||||
|
||||
@page
|
||||
@node Ref.Mem.Acct
|
||||
@ -1245,10 +1276,10 @@ messages. Ports receive messages from channels.
|
||||
A @dfn{channel} is a communication endpoint that can @emph{send}
|
||||
messages. Channels send messages to ports.
|
||||
|
||||
Each port has a unique identity and cannot be replicated. If a port value is
|
||||
copied from one slot to another, both slots refer to the @emph{same} port,
|
||||
even if the slots are declared as interior-mode. New ports can be constructed
|
||||
dynamically and stored in data structures.
|
||||
Each port is implicitly boxed and mutable; as such a port has has a unique
|
||||
per-task identity and cannot be replicated or transmitted. If a port value is
|
||||
copied, both copies refer to the @emph{same} port. New ports can be
|
||||
constructed dynamically and stored in data structures.
|
||||
|
||||
Each channel is bound to a port when the channel is constructed, so the
|
||||
destination port for a channel must exist before the channel itself. A channel
|
||||
@ -1672,8 +1703,8 @@ Rust; they cannot be used as user-defined identifiers in any context.
|
||||
@subsection Ref.Type.Any
|
||||
|
||||
The type @code{any} is the union of all possible Rust types. A value of type
|
||||
@code{any} is represented in memory as a pair consisting of an exterior value
|
||||
of some non-@code{any} type @var{T} and a reflection of the type @var{T}.
|
||||
@code{any} is represented in memory as a pair consisting of a boxed value of
|
||||
some non-@code{any} type @var{T} and a reflection of the type @var{T}.
|
||||
|
||||
Values of type @code{any} can be used in an @code{alt type} statement, in
|
||||
which the reflection is used to select a block corresponding to a particular
|
||||
@ -1754,10 +1785,10 @@ The primitive types are the following:
|
||||
@item
|
||||
The ``nil'' type @code{()}, having the single ``nil'' value
|
||||
@code{()}.@footnote{The ``nil'' value @code{()} is @emph{not} a sentinel
|
||||
``null pointer'' value for alias or exterior slots; the ``nil'' type is the
|
||||
implicit return type from functions otherwise lacking a return type, and can
|
||||
be used in other contexts (such as message-sending or type-parametric code) as
|
||||
a zero-byte type.}
|
||||
``null pointer'' value for alias slots; the ``nil'' type is the implicit
|
||||
return type from functions otherwise lacking a return type, and can be used in
|
||||
other contexts (such as message-sending or type-parametric code) as a
|
||||
zero-size type.}
|
||||
@item
|
||||
The boolean type @code{bool} with values @code{true} and @code{false}.
|
||||
@item
|
||||
@ -1798,7 +1829,7 @@ A value of type @code{str} is a Unicode string, represented as a vector of
|
||||
@subsection Ref.Type.Rec
|
||||
|
||||
The record type-constructor @code{rec} forms a new heterogeneous product of
|
||||
slots.@footnote{The @code{rec} type-constructor is analogous to the
|
||||
values.@footnote{The @code{rec} type-constructor is analogous to the
|
||||
@code{struct} type-constructor in the Algol/C family, the @emph{record} types
|
||||
of the ML family, or the @emph{structure} types of the Lisp family.} Fields of
|
||||
a @code{rec} type are accessed by name and are arranged in memory in the order
|
||||
@ -1816,10 +1847,10 @@ let int px = p.x;
|
||||
@subsection Ref.Type.Tup
|
||||
|
||||
The tuple type-constructor @code{tup} forms a new heterogeneous product of
|
||||
slots exactly as the @code{rec} type-constructor does, with the difference
|
||||
that tuple slots are automatically assigned implicit field names, given by
|
||||
values exactly as the @code{rec} type-constructor does, with the difference
|
||||
that tuple members are automatically assigned implicit field names, given by
|
||||
ascending integers prefixed by the underscore character: @code{_0}, @code{_1},
|
||||
@code{_2}, etc. The fields of a tuple are laid out in memory contiguously,
|
||||
@code{_2}, etc. The members of a tuple are laid out in memory contiguously,
|
||||
like a record, in order specified by the tuple type.
|
||||
|
||||
An example of a tuple type and its use:
|
||||
@ -1837,9 +1868,9 @@ check (p._1 == "world");
|
||||
@subsection Ref.Type.Vec
|
||||
|
||||
The vector type-constructor @code{vec} represents a homogeneous array of
|
||||
slots. A vector has a fixed size, and may or may not have mutable member
|
||||
slots. If the slots of a vector are mutable, the vector is a @emph{state}
|
||||
type.
|
||||
values of a given type. A vector has a fixed size. If the member-type of a
|
||||
vector is a state type, then vector is a @emph{state} type, like any type
|
||||
containing another type.
|
||||
|
||||
Vectors can be sliced. A slice expression builds a new vector by copying a
|
||||
contiguous range -- given by a pair of indices representing a half-open
|
||||
@ -1854,8 +1885,8 @@ let vec[int] v2 = v.(0,1); // Form a slice.
|
||||
|
||||
Vectors always @emph{allocate} a storage region sufficient to store the first
|
||||
power of two worth of elements greater than or equal to the size of the
|
||||
largest slice sharing the storage. This behaviour supports idiomatic in-place
|
||||
``growth'' of a mutable slot holding a vector:
|
||||
vector. This behaviour supports idiomatic in-place ``growth'' of a mutable
|
||||
slot holding a vector:
|
||||
|
||||
@example
|
||||
let mutable vec[int] v = vec(1, 2, 3);
|
||||
@ -1888,8 +1919,8 @@ a @code{tag} type may refer to type definitions that include the defined
|
||||
@item Recursive types can only be introduced through @code{tag} types.
|
||||
@item A recursive @code{tag} type must have at least one non-recursive
|
||||
variant (in order to give the recursion a basis case).
|
||||
@item The recursive slots of recursive variants must be @emph{exterior}
|
||||
slots (in order to bound the in-memory size of the variant).
|
||||
@item The recursively-typed members of recursive variants must be @emph{box}
|
||||
values (in order to bound the in-memory size of the variant).
|
||||
@item Recursive type definitions can cross module boundaries, but not module
|
||||
@emph{visibility} boundaries, nor crate boundaries (in order to simplify the
|
||||
module system).
|
||||
@ -2028,7 +2059,7 @@ Like ports, tasks are modeled as mutable native types with built-in meaning to
|
||||
the language. They cannot be transmitted over channels or otherwise
|
||||
replicated, and are always local to the task that spawns them.
|
||||
|
||||
If all references to a task are dropped (due to the release of any slots
|
||||
If all references to a task are dropped (due to the release of any structure
|
||||
holding those references), the released task immediately fails.
|
||||
@xref{Ref.Task.Life}.
|
||||
|
||||
@ -2163,7 +2194,7 @@ actions.
|
||||
@menu
|
||||
* Ref.Stmt.Stat:: The static typestate system of statement analysis.
|
||||
* Ref.Stmt.Decl:: Statement declaring an item or slot.
|
||||
* Ref.Stmt.Copy:: Statement for copying a value between two slots.
|
||||
* Ref.Stmt.Copy:: Statement for copying a value.
|
||||
* Ref.Stmt.Spawn:: Statements for creating new tasks.
|
||||
* Ref.Stmt.Send:: Statements for sending a value into a channel.
|
||||
* Ref.Stmt.Flush:: Statement for flushing a channel queue.
|
||||
@ -2198,7 +2229,7 @@ on a statement-by-statement basis, the @emph{effects} the statement has on its
|
||||
environment, as well the @emph{legality} of the statement in its environment.
|
||||
|
||||
The legality of a statement is partly governed by syntactic rules, partly by
|
||||
its conformance to the types of slots it affects, and partly by a
|
||||
its conformance to the types of value it affects, and partly by a
|
||||
statement-oriented static dataflow analysis. This section describes the
|
||||
statement-oriented static dataflow analysis, also called the @emph{typestate}
|
||||
system.
|
||||
@ -2427,13 +2458,13 @@ declaring a function-local item.
|
||||
A @code{slot declaration statement} has one one of two forms:
|
||||
|
||||
@itemize
|
||||
@item @code{let} @var{mode-and-type} @var{slot} @var{optional-init};
|
||||
@item @code{let} @var{type} @var{slot} @var{optional-init};
|
||||
@item @code{auto} @var{slot} @var{optional-init};
|
||||
@end itemize
|
||||
|
||||
Where @var{mode-and-type} is a slot mode and type expression, @var{slot} is
|
||||
the name of the slot being declared, and @var{optional-init} is either the
|
||||
empty string or an equals sign (@code{=}) followed by a primitive expression.
|
||||
Where @var{type} is a type expression, @var{slot} is the name of the slot
|
||||
being declared, and @var{optional-init} is either the empty string or an
|
||||
equals sign (@code{=}) followed by a primitive expression.
|
||||
|
||||
Both forms introduce a new slot into the containing block scope. The new slot
|
||||
is visible across the entire scope, but is initialized only at the point
|
||||
@ -2441,28 +2472,30 @@ following the declaration statement.
|
||||
|
||||
The latter (@code{auto}) form of slot declaration causes the compiler to infer
|
||||
the static type of the slot through unification with the types of values
|
||||
assigned to the slot in the the remaining code in the block scope. Inferred
|
||||
slots always have @emph{interior} mode. @xref{Ref.Mem.Slot}.
|
||||
assigned to the slot in the the remaining code in the block scope. Inference
|
||||
only occurs on frame-local slots, not argument slots. Function, iterator and
|
||||
object signatures must always declared types for all argument slots.
|
||||
@xref{Ref.Mem.Slot}.
|
||||
|
||||
|
||||
|
||||
@page
|
||||
@node Ref.Stmt.Copy
|
||||
@subsection Ref.Stmt.Copy
|
||||
@c * Ref.Stmt.Copy:: Statement for copying a value between two slots.
|
||||
@c * Ref.Stmt.Copy:: Statement for copying a value.
|
||||
|
||||
A @dfn{copy statement} consists of an @emph{lval} -- a name denoting a slot --
|
||||
followed by an equals-sign (@code{=}) and a primitive
|
||||
expression. @xref{Ref.Expr}.
|
||||
A @dfn{copy statement} consists of an @emph{lval} followed by an equals-sign
|
||||
(@code{=}) and a primitive expression. @xref{Ref.Expr}.
|
||||
|
||||
Executing a copy statement causes the value denoted by the expression --
|
||||
either a value in a slot or a primitive combination of values held in slots --
|
||||
to be copied into the slot denoted by the @emph{lval}.
|
||||
either a value or a primitive combination of values -- to be copied into the
|
||||
memory location denoted by the @emph{lval}.
|
||||
|
||||
A copy may entail the formation of references, the adjustment of reference
|
||||
counts, execution of destructors, or similar adjustments in order to respect
|
||||
the @code{lval} slot mode and any existing value held in it. All such
|
||||
adjustment is automatic and implied by the @code{=} operator.
|
||||
A copy may entail the the adjustment of reference counts, execution of
|
||||
destructors, or similar adjustments in order to respect the path through the
|
||||
memory graph implied by the @code{lval}, as well as any existing value held in
|
||||
the memory being written-to. All such adjustment is automatic and implied by
|
||||
the @code{=} operator.
|
||||
|
||||
An example of three different copy statements:
|
||||
@example
|
||||
@ -2483,8 +2516,8 @@ function. The called function is referred to as the @dfn{entry function} for
|
||||
the spawned task, and its arguments are copied form the spawning task to the
|
||||
spawned task before the spawned task begins execution.
|
||||
|
||||
Only arguments of interior or exterior mode are permitted in the function
|
||||
called by a spawn statement, not arguments with alias mode.
|
||||
Functions taking alias-slot arguments, or returning non-nil values, cannot be
|
||||
spawned. Iterators cannot be spawned.
|
||||
|
||||
The result of a @code{spawn} statement is a @code{task} value.
|
||||
|
||||
@ -2561,8 +2594,8 @@ expression denoting a port, and applies the @emph{receive operator}
|
||||
@var{lval}. The statement causes the receiving task to enter the @emph{blocked
|
||||
reading} state until a task is sending a value to the port, at which point the
|
||||
runtime pseudo-randomly selects a sending task and copies a value from the
|
||||
head of one of the task queues to the receiving slot, and un-blocks the
|
||||
receiving task. @xref{Ref.Run.Comm}.
|
||||
head of one of the task queues to the receiving location in memory, and
|
||||
un-blocks the receiving task. @xref{Ref.Run.Comm}.
|
||||
|
||||
An example of a @emph{receive}:
|
||||
@example
|
||||
@ -2576,7 +2609,8 @@ let str s <- p;
|
||||
@c * Ref.Stmt.Call:: Statement for calling a function.
|
||||
|
||||
A @dfn{call statement} invokes a function, providing a tuple of input slots
|
||||
and a reference to an output slot. If the function eventually returns, then
|
||||
and an alias slot to serve as the function's output, bound to the @var{lval}
|
||||
on the right hand side of the call. If the function eventually returns, then
|
||||
the statement completes.
|
||||
|
||||
A call statement statically requires that the precondition declared in the
|
||||
@ -2596,7 +2630,7 @@ let int x = add(1, 2);
|
||||
A @dfn{bind statement} constructs a new function from an existing
|
||||
function.@footnote{The @code{bind} statement is analogous to the @code{bind}
|
||||
expression in the Sather language.} The new function has zero or more of its
|
||||
arguments @emph{bound} into a new, hidden exterior tuple that holds the
|
||||
arguments @emph{bound} into a new, hidden boxed tuple that holds the
|
||||
bindings. For each concrete argument passed in the @code{bind} statement, the
|
||||
corresponding parameter in the existing function is @emph{omitted} as a
|
||||
parameter of the new function. For each argument passed the placeholder symbol
|
||||
@ -2624,11 +2658,9 @@ check (add(4,5) == add5(4));
|
||||
@end example
|
||||
|
||||
A @code{bind} statement generally stores a copy of the bound arguments in the
|
||||
hidden exterior tuple. For bound interior slots and alias slots in the bound
|
||||
function signature, an interior slot is allocated in the hidden tuple and
|
||||
populated with a copy of the bound value. For bound exterior slots in the
|
||||
bound function signature, an exterior slot is allocated in the hidden tuple
|
||||
and populated with a copy of the bound value, an exterior (pointer) value.
|
||||
hidden, boxed tuple, owned by the resulting first-class function. For each
|
||||
bound slot in the bound function's signature, space is allocated in the hidden
|
||||
tuple and populated with a copy of the bound value.
|
||||
|
||||
The @code{bind} statement is a lightweight mechanism for simulating the more
|
||||
elaborate construct of @emph{lexical closures} that exist in other
|
||||
@ -2641,11 +2673,10 @@ of them can be achieved with @code{bind} statements.
|
||||
@subsection Ref.Stmt.Ret
|
||||
@c * Ref.Stmt.Ret:: Statement for stopping and producing a value.
|
||||
|
||||
Executing a @code{ret} statement@footnote{A @code{ret} statement is
|
||||
analogous to a @code{return} statement in the C family.} copies a
|
||||
value into the return slot of the current function, destroys the
|
||||
current function activation frame, and transfers control to the caller
|
||||
frame.
|
||||
Executing a @code{ret} statement@footnote{A @code{ret} statement is analogous
|
||||
to a @code{return} statement in the C family.} copies a value into the output
|
||||
slot of the current function, destroys the current function activation frame,
|
||||
and transfers control to the caller frame.
|
||||
|
||||
An example of a @code{ret} statement:
|
||||
@example
|
||||
@ -2692,7 +2723,7 @@ copy of itself.
|
||||
@subsection Ref.Stmt.Put
|
||||
@c * Ref.Stmt.Put:: Statement for pausing and producing a value.
|
||||
|
||||
Executing a @code{put} statement copies a value into the put slot of the
|
||||
Executing a @code{put} statement copies a value into the output slot of the
|
||||
current iterator, suspends execution of the current iterator, and transfers
|
||||
control to the current put-recipient frame.
|
||||
|
||||
@ -2772,13 +2803,12 @@ In this example, if the task fails while attempting to open or read a file,
|
||||
the runtime will log the path name that was being read. If the function
|
||||
completes normally, the runtime will not log the path.
|
||||
|
||||
A slot that is marked by a @code{note} statement does @emph{not} have its
|
||||
value copied aside when control passes through the @code{note}. In other
|
||||
words, if a @code{note} statement notes a particular slot, and code after the
|
||||
@code{note} that slot, and then a subsequent failure occurs, the
|
||||
@emph{mutated} value will be logged during unwinding, @emph{not} the original
|
||||
value that was held in the slot at the moment control passed through the
|
||||
@code{note} statement.
|
||||
A value that is marked by a @code{note} statement is @emph{not} copied aside
|
||||
when control passes through the @code{note}. In other words, if a @code{note}
|
||||
statement notes a particular @var{lval}, and code after the @code{note} that
|
||||
slot, and then a subsequent failure occurs, the @emph{mutated} value will be
|
||||
logged during unwinding, @emph{not} the original value that was denoted by the
|
||||
@var{lval} at the moment control passed through the @code{note} statement.
|
||||
|
||||
@page
|
||||
@node Ref.Stmt.While
|
||||
@ -3124,7 +3154,7 @@ if check even(x) @{
|
||||
The Rust @dfn{runtime} is a relatively compact collection of C and Rust code
|
||||
that provides fundamental services and datatypes to all Rust tasks at
|
||||
run-time. It is smaller and simpler than many modern language runtimes. It is
|
||||
tightly integrated into the language's execution model of slots, tasks,
|
||||
tightly integrated into the language's execution model of memory, tasks,
|
||||
communication, reflection, logging and signal handling.
|
||||
|
||||
@menu
|
||||
@ -3149,7 +3179,7 @@ of the C runtime functions @code{malloc} and @code{free}.
|
||||
|
||||
The runtime memory-management system in turn supplies Rust tasks with
|
||||
facilities for allocating, extending and releasing stacks, as well as
|
||||
allocating and freeing exterior values.
|
||||
allocating and freeing boxed values.
|
||||
|
||||
@page
|
||||
@node Ref.Run.Type
|
||||
|
Loading…
Reference in New Issue
Block a user