diff options
| author | Graydon Hoare <[email protected]> | 2010-12-14 13:41:19 -0800 |
|---|---|---|
| committer | Graydon Hoare <[email protected]> | 2010-12-14 13:41:19 -0800 |
| commit | 3f227c71b21c0a6962d8529b4ce8b725bde69a8c (patch) | |
| tree | 9442eefdd1616a003617d471e8e3c4a5cafdab33 | |
| parent | Make failing to resolve a symbol an error (diff) | |
| download | rust-3f227c71b21c0a6962d8529b4ce8b725bde69a8c.tar.xz rust-3f227c71b21c0a6962d8529b4ce8b725bde69a8c.zip | |
Some terminology updates to talk about layers.
| -rw-r--r-- | doc/rust.texi | 150 |
1 files changed, 78 insertions, 72 deletions
diff --git a/doc/rust.texi b/doc/rust.texi index 1576f4f8..5fc1a8b7 100644 --- a/doc/rust.texi +++ b/doc/rust.texi @@ -250,9 +250,7 @@ Many values in Rust are allocated @emph{within} their containing stack-frame or parent structure. 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. +value, its @emph{content}. Boxing and unboxing in Rust is explicit, though in many cases (arithmetic operations, name-component dereferencing) Rust will automatically ``reach @@ -275,35 +273,42 @@ still guaranteeing that every use of a slot occurs after it has been initialized. @sp 1 -@item Static control over mutability. +@item Static control over mutability and garbage collection. -Types in Rust are classified as either immutable or mutable. By default, -all types are immutable. +Types in Rust are classified into @emph{layers}. There is a layer of immutable +values, a layer of state values, and a layer of GC values. 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. +If a field within a type is declared as @code{mutable}, then the type is part +of the @code{state} layer and must be declared as such. Any type directly +marked as @code{state} @emph{or indirectly referring to} 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: +If a field within a type is potentially cyclic (this is a narrow, but +well-defined condition involving mutable recursive types) then it is part of +the @code{gc} layer and must be declared as such. + +This classification of data types in Rust interacts with the memory allocation, +transmission and destruction 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. +@item Only immutable values can be sent over channels. +@item Only non-GC 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. +Garbage collection, when present, operates per-task and does not interrupt +other tasks while running. It is limited to types that need it and can be +statically avoided altogether by limiting the types in a program to the state +and immutable layers. -Boxed immutable values are reference-counted and have a deterministic -destruction order: top-down, immediately upon release of the last live -reference. +Non-GC 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 non-state 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. +State values can refer to non-state values, but not vice-versa; likewise GC +values can refer to non-GC 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, +and provides local (per-task) GC only when required. @sp 1 @item Stack-based iterators @@ -360,8 +365,7 @@ Rust has a lightweight object system based on structural object types: there is no ``class hierarchy'' nor any concept of inheritance. Method overriding and object restriction are performed explicitly on object values, which are little more than order-insensitive records of methods sharing a common private -value. Objects can be state or non-state, and only non-state objects can have -destructors. +value. Objects that reside outside the GC layer can have destructors. @sp 1 @item Dynamic type @@ -407,29 +411,29 @@ organizing tasks into mutually-supervising or mutually-failing groups. @sp 1 @item Deterministic destruction -Immutable objects can have destructor functions, which are executed +Non-GC objects can have destructor functions, which are executed deterministically in top-down ownership order, as control frames are exited 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 values are deterministic and +Similarly, the rules for freeing non-GC 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. -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 +GC values are local to a task, and are subject to per-task garbage +collection. As a result, unreferenced GC-layer boxes are not necessarily freed +immediately; if an unreferenced GC 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). -State values can point to immutable values but not vice-versa. Doing so merely +GC values can point to non-GC 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 +top-down destruction sequence for the referenced non-GC values +@emph{start}. In other words, the non-GC ``leaves'' of a GC value are released +in a locally-predictable order, even if the ``interior'' cyclic part of the GC value is released in an unpredictable order. @sp 1 @@ -1265,15 +1269,16 @@ 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 boxes: -@emph{task-local} state boxes and the @emph{shared} non-state boxes. +@emph{task-local} state and GC boxes, and the @emph{shared} immutable boxes. -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 +State and GC boxes are @dfn{task-local}, owned by the task. Like any other +state or GC value, they cannot pass over channels. State and GC boxes do not +outlive the task that owns them. When unreferenced, they are either +immediately destructed (if acyclic) or else 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. -Non-state boxes are @dfn{shared}, and can be multiply-referenced by many +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 @@ -1794,9 +1799,9 @@ statement. If a control path lacks a @code{ret} statement in source code, an implicit @code{ret} statement is appended to the end of the control path during compilation, returning the implicit @code{()} value. -A function may have an @emph{effect}, which may be either @code{io}, -@code{state}, @code{unsafe}. If no effect is specified, the function is said -to be @dfn{pure}. +A function may have an @emph{effect}, which may be either @code{impure} or +@code{unsafe}. If no effect is specified, the function is said to be +@dfn{pure}. Any pure boolean function is also called a @emph{predicate}, and may be used as part of the static typestate system. @xref{Ref.Stmt.Stat.Constr}. @@ -1933,23 +1938,23 @@ variables to initial values. @c * Ref.Item.Type:: Items defining the types of values and slots. @cindex Types -A @dfn{type} defines an @emph{interpretation} of a value in -memory. @xref{Ref.Type}. Types are declared with the keyword @code{type}. A -type's interpretation is used for the values held in any slot with that -type. @xref{Ref.Mem.Slot}. The interpretation of a value includes: +A @dfn{type} defines a set of possible values in +memory. @xref{Ref.Type}. Types are declared with the keyword +@code{type}. Every value has a single, specific type; the type-specified +aspects of a value include: @itemize @item Whether the value is composed of sub-values or is indivisible. @item Whether the value represents textual or numerical information. @item Whether the value represents integral or floating-point information. @item The sequence of memory operations required to access the value. -@item Whether the value is mutable or immutable. +@item The storage layer the value resides in (immutable, state or gc). @end itemize -For example, the type @code{rec(u8 x, u8 y)} defines the interpretation of -values that are composite records, each containing two unsigned 8-bit -integers accessed through the components @code{x} and @code{y}, and laid -out in memory with the @code{x} component preceding the @code{y} component. +For example, the type @code{rec(u8 x, u8 y)} defines the set of immutable +values that are composite records, each containing two unsigned 8-bit integers +accessed through the components @code{x} and @code{y}, and laid out in memory +with the @code{x} component preceding the @code{y} component. @node Ref.Item.Tag @subsection Ref.Item.Tag @@ -2238,9 +2243,9 @@ check (p._1 == "world"); @cindex Array types, see @i{Vector types} The vector type-constructor @code{vec} represents a homogeneous array of -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. +values of a given type. A vector has a fixed size. The layer of a vector type +is to the layer of its member type, like any type that contains a single +member 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 @@ -2342,10 +2347,13 @@ communication facility. @xref{Ref.Task.Comm}. A @code{port} type takes a single type parameter, denoting the type of value that can be received from a @code{port} value of that type. -Ports are modeled as mutable native types with built-in meaning to the +Ports are modeled as stateful 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 creates them. +Ports (like channels) can only be carry types of the immutable layer. No +mutable values can pass over a port or channel. + An example of a @code{port} type: @example type port[vec[str]] svp; @@ -2369,6 +2377,9 @@ Channels are immutable, and can be transmitted over channels to other tasks. They are modeled as immutable native types with built-in meaning to the language. +Channels (like ports) can only be carry types of the immutable layer. No +mutable values can pass over a port or channel. + When a task sends a message into a channel, the task forms an outgoing queue associated with that channel. The per-task queue @emph{associated} with a channel can be indirectly manipulated by the task, but is @emph{not} otherwise @@ -2379,8 +2390,8 @@ associated with the channel. Channels are also @emph{weak}: a channel is directly coupled to a particular destination port on a particular task, but does not keep that port or task @emph{alive}. A channel may therefore fail to operate at any moment. If a task -sends to a channel that is connected to a nonexistent port, it receives a -signal. +sends a message to a channel that is connected to a nonexistent port, the +message is dropped. An example of a @code{chan} type: @example @@ -2407,8 +2418,8 @@ 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 structure -holding those references), the released task immediately fails. -@xref{Ref.Task.Life}. +holding those references), the runtime signals the un-referenced task, which +then fails. @xref{Ref.Task.Life}. @node Ref.Type.Obj @@ -2427,15 +2438,10 @@ declaration. Such a ``plain'' object type can be used to describe an interface that a variety of particular objects may conform to, by supporting a superset of the methods. -An object type that can contain a state must be declared as a @code{state obj} -like any other state type. And similarly a method type that performs I/O or -makes native calls must be declared @code{io} or @code{unsafe}, like any other -function. - -Moreover, @emph{all} methods of a state object are implicitly state functions -- as -they all bind the same mutable state field(s) -- so implicitly have an effect -lower than @code{io}. It is therefore unnecessary to declare methods within a -state object type (or state object item) as @code{io}. +An object type that can contain fields of a given layer must be declared as +residing in that layer (or lower), like any other type. And similarly a method +with a given effect must be declared as having that effect (or lower) in the +object type, like any other function. An example of an object type with two separate object items supporting it, and a client function using both items via the object type: @@ -2444,17 +2450,17 @@ a client function using both items via the object type: state type taker = state obj @{ - fn take(int); + impure fn take(int); @}; state obj adder(mutable int x) @{ - fn take(int y) @{ + impure fn take(int y) @{ x += y; @} @} obj sender(chan[int] c) @{ - io fn take(int z) @{ + impure fn take(int z) @{ c <| z; @} @} @@ -3113,7 +3119,7 @@ by the runtime or emitted to a system console. Log statements are enabled or disabled dynamically at run-time on a per-task and per-item basis. @xref{Ref.Run.Log}. -Executing a @code{log} statement is not considered an @code{io} effect in the +Executing a @code{log} statement is not considered an impure effect in the effect system. In other words, a pure function remains pure even if it contains a log statement. |