From 287a3457bcfb07e65ddc16affd8f721ad7cfa29c Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 15 Feb 2017 17:55:02 -0500 Subject: [PATCH] clean up some things I double checked that everything is here and in the correct order; this fixes things up --- src/doc/reference/src/items.md | 371 +++++++++++++++++++++++++- src/doc/reference/src/memory-model.md | 14 - src/doc/reference/src/tokens.md | 11 + src/doc/reference/src/unsafety.md | 29 -- 4 files changed, 381 insertions(+), 44 deletions(-) diff --git a/src/doc/reference/src/items.md b/src/doc/reference/src/items.md index 0b4421de2a9..9f667e7a3c4 100644 --- a/src/doc/reference/src/items.md +++ b/src/doc/reference/src/items.md @@ -630,7 +630,7 @@ unsafe fn bump_levels_unsafe2() -> u32 { Mutable statics have the same restrictions as normal statics, except that the type of the value is not required to ascribe to `Sync`. -### `'static` lifetime elision +#### `'static` lifetime elision [Unstable] Both constant and static declarations of reference types have *implicit* `'static` lifetimes unless an explicit lifetime is specified. As @@ -676,3 +676,372 @@ const RESOLVED_MULTIPLE: Fn(&Foo, &Bar, &Baz) -> usize = .. // `Fn(&'static Foo, &'static Bar) -> &'static Baz`. const RESOLVED_STATIC: Fn(&Foo, &Bar) -> &Baz = .. ``` + +### Traits + +A _trait_ describes an abstract interface that types can +implement. This interface consists of associated items, which come in +three varieties: + +- functions +- constants +- types + +Associated functions whose first parameter is named `self` are called +methods and may be invoked using `.` notation (e.g., `x.foo()`). + +All traits define an implicit type parameter `Self` that refers to +"the type that is implementing this interface". Traits may also +contain additional type parameters. These type parameters (including +`Self`) may be constrained by other traits and so forth as usual. + +Trait bounds on `Self` are considered "supertraits". These are +required to be acyclic. Supertraits are somewhat different from other +constraints in that they affect what methods are available in the +vtable when the trait is used as a [trait object](#trait-objects). + +Traits are implemented for specific types through separate +[implementations](#implementations). + +Consider the following trait: + +``` +# type Surface = i32; +# type BoundingBox = i32; +trait Shape { + fn draw(&self, Surface); + fn bounding_box(&self) -> BoundingBox; +} +``` + +This defines a trait with two methods. All values that have +[implementations](#implementations) of this trait in scope can have their +`draw` and `bounding_box` methods called, using `value.bounding_box()` +[syntax](#method-call-expressions). + +Traits can include default implementations of methods, as in: + +``` +trait Foo { + fn bar(&self); + fn baz(&self) { println!("We called baz."); } +} +``` + +Here the `baz` method has a default implementation, so types that implement +`Foo` need only implement `bar`. It is also possible for implementing types +to override a method that has a default implementation. + +Type parameters can be specified for a trait to make it generic. These appear +after the trait name, using the same syntax used in [generic +functions](#generic-functions). + +``` +trait Seq { + fn len(&self) -> u32; + fn elt_at(&self, n: u32) -> T; + fn iter(&self, F) where F: Fn(T); +} +``` + +It is also possible to define associated types for a trait. Consider the +following example of a `Container` trait. Notice how the type is available +for use in the method signatures: + +``` +trait Container { + type E; + fn empty() -> Self; + fn insert(&mut self, Self::E); +} +``` + +In order for a type to implement this trait, it must not only provide +implementations for every method, but it must specify the type `E`. Here's +an implementation of `Container` for the standard library type `Vec`: + +``` +# trait Container { +# type E; +# fn empty() -> Self; +# fn insert(&mut self, Self::E); +# } +impl Container for Vec { + type E = T; + fn empty() -> Vec { Vec::new() } + fn insert(&mut self, x: T) { self.push(x); } +} +``` + +Generic functions may use traits as _bounds_ on their type parameters. This +will have two effects: + +- Only types that have the trait may instantiate the parameter. +- Within the generic function, the methods of the trait can be + called on values that have the parameter's type. + +For example: + +``` +# type Surface = i32; +# trait Shape { fn draw(&self, Surface); } +fn draw_twice(surface: Surface, sh: T) { + sh.draw(surface); + sh.draw(surface); +} +``` + +Traits also define a [trait object](#trait-objects) with the same +name as the trait. Values of this type are created by coercing from a +pointer of some specific type to a pointer of trait type. For example, +`&T` could be coerced to `&Shape` if `T: Shape` holds (and similarly +for `Box`). This coercion can either be implicit or +[explicit](#type-cast-expressions). Here is an example of an explicit +coercion: + +``` +trait Shape { } +impl Shape for i32 { } +let mycircle = 0i32; +let myshape: Box = Box::new(mycircle) as Box; +``` + +The resulting value is a box containing the value that was cast, along with +information that identifies the methods of the implementation that was used. +Values with a trait type can have [methods called](#method-call-expressions) on +them, for any method in the trait, and can be used to instantiate type +parameters that are bounded by the trait. + +Trait methods may be static, which means that they lack a `self` argument. +This means that they can only be called with function call syntax (`f(x)`) and +not method call syntax (`obj.f()`). The way to refer to the name of a static +method is to qualify it with the trait name, treating the trait name like a +module. For example: + +``` +trait Num { + fn from_i32(n: i32) -> Self; +} +impl Num for f64 { + fn from_i32(n: i32) -> f64 { n as f64 } +} +let x: f64 = Num::from_i32(42); +``` + +Traits may inherit from other traits. Consider the following example: + +``` +trait Shape { fn area(&self) -> f64; } +trait Circle : Shape { fn radius(&self) -> f64; } +``` + +The syntax `Circle : Shape` means that types that implement `Circle` must also +have an implementation for `Shape`. Multiple supertraits are separated by `+`, +`trait Circle : Shape + PartialEq { }`. In an implementation of `Circle` for a +given type `T`, methods can refer to `Shape` methods, since the typechecker +checks that any type with an implementation of `Circle` also has an +implementation of `Shape`: + +```rust +struct Foo; + +trait Shape { fn area(&self) -> f64; } +trait Circle : Shape { fn radius(&self) -> f64; } +impl Shape for Foo { + fn area(&self) -> f64 { + 0.0 + } +} +impl Circle for Foo { + fn radius(&self) -> f64 { + println!("calling area: {}", self.area()); + + 0.0 + } +} + +let c = Foo; +c.radius(); +``` + +In type-parameterized functions, methods of the supertrait may be called on +values of subtrait-bound type parameters. Referring to the previous example of +`trait Circle : Shape`: + +``` +# trait Shape { fn area(&self) -> f64; } +# trait Circle : Shape { fn radius(&self) -> f64; } +fn radius_times_area(c: T) -> f64 { + // `c` is both a Circle and a Shape + c.radius() * c.area() +} +``` + +Likewise, supertrait methods may also be called on trait objects. + +```{.ignore} +# trait Shape { fn area(&self) -> f64; } +# trait Circle : Shape { fn radius(&self) -> f64; } +# impl Shape for i32 { fn area(&self) -> f64 { 0.0 } } +# impl Circle for i32 { fn radius(&self) -> f64 { 0.0 } } +# let mycircle = 0i32; +let mycircle = Box::new(mycircle) as Box; +let nonsense = mycircle.radius() * mycircle.area(); +``` + +### Implementations + +An _implementation_ is an item that implements a [trait](#traits) for a +specific type. + +Implementations are defined with the keyword `impl`. + +``` +# #[derive(Copy, Clone)] +# struct Point {x: f64, y: f64}; +# type Surface = i32; +# struct BoundingBox {x: f64, y: f64, width: f64, height: f64}; +# trait Shape { fn draw(&self, Surface); fn bounding_box(&self) -> BoundingBox; } +# fn do_draw_circle(s: Surface, c: Circle) { } +struct Circle { + radius: f64, + center: Point, +} + +impl Copy for Circle {} + +impl Clone for Circle { + fn clone(&self) -> Circle { *self } +} + +impl Shape for Circle { + fn draw(&self, s: Surface) { do_draw_circle(s, *self); } + fn bounding_box(&self) -> BoundingBox { + let r = self.radius; + BoundingBox { + x: self.center.x - r, + y: self.center.y - r, + width: 2.0 * r, + height: 2.0 * r, + } + } +} +``` + +It is possible to define an implementation without referring to a trait. The +methods in such an implementation can only be used as direct calls on the values +of the type that the implementation targets. In such an implementation, the +trait type and `for` after `impl` are omitted. Such implementations are limited +to nominal types (enums, structs, trait objects), and the implementation must +appear in the same crate as the `self` type: + +``` +struct Point {x: i32, y: i32} + +impl Point { + fn log(&self) { + println!("Point is at ({}, {})", self.x, self.y); + } +} + +let my_point = Point {x: 10, y:11}; +my_point.log(); +``` + +When a trait _is_ specified in an `impl`, all methods declared as part of the +trait must be implemented, with matching types and type parameter counts. + +An implementation can take type parameters, which can be different from the +type parameters taken by the trait it implements. Implementation parameters +are written after the `impl` keyword. + +``` +# trait Seq { fn dummy(&self, _: T) { } } +impl Seq for Vec { + /* ... */ +} +impl Seq for u32 { + /* Treat the integer as a sequence of bits */ +} +``` + +### External blocks + +External blocks form the basis for Rust's foreign function interface. +Declarations in an external block describe symbols in external, non-Rust +libraries. + +Functions within external blocks are declared in the same way as other Rust +functions, with the exception that they may not have a body and are instead +terminated by a semicolon. + +Functions within external blocks may be called by Rust code, just like +functions defined in Rust. The Rust compiler automatically translates between +the Rust ABI and the foreign ABI. + +Functions within external blocks may be variadic by specifying `...` after one +or more named arguments in the argument list: + +```ignore +extern { + fn foo(x: i32, ...); +} +``` + +A number of [attributes](#ffi-attributes) control the behavior of external blocks. + +By default external blocks assume that the library they are calling uses the +standard C ABI on the specific platform. Other ABIs may be specified using an +`abi` string, as shown here: + +```ignore +// Interface to the Windows API +extern "stdcall" { } +``` + +There are three ABI strings which are cross-platform, and which all compilers +are guaranteed to support: + +* `extern "Rust"` -- The default ABI when you write a normal `fn foo()` in any + Rust code. +* `extern "C"` -- This is the same as `extern fn foo()`; whatever the default + your C compiler supports. +* `extern "system"` -- Usually the same as `extern "C"`, except on Win32, in + which case it's `"stdcall"`, or what you should use to link to the Windows API + itself + +There are also some platform-specific ABI strings: + +* `extern "cdecl"` -- The default for x86\_32 C code. +* `extern "stdcall"` -- The default for the Win32 API on x86\_32. +* `extern "win64"` -- The default for C code on x86\_64 Windows. +* `extern "sysv64"` -- The default for C code on non-Windows x86\_64. +* `extern "aapcs"` -- The default for ARM. +* `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's + `__fastcall` and GCC and clang's `__attribute__((fastcall))` +* `extern "vectorcall"` -- The `vectorcall` ABI -- corresponds to MSVC's + `__vectorcall` and clang's `__attribute__((vectorcall))` + +Finally, there are some rustc-specific ABI strings: + +* `extern "rust-intrinsic"` -- The ABI of rustc intrinsics. +* `extern "rust-call"` -- The ABI of the Fn::call trait functions. +* `extern "platform-intrinsic"` -- Specific platform intrinsics -- like, for + example, `sqrt` -- have this ABI. You should never have to deal with it. + +The `link` attribute allows the name of the library to be specified. When +specified the compiler will attempt to link against the native library of the +specified name. + +```{.ignore} +#[link(name = "crypto")] +extern { } +``` + +The type of a function declared in an extern block is `extern "abi" fn(A1, ..., +An) -> R`, where `A1...An` are the declared types of its arguments and `R` is +the declared return type. + +It is valid to add the `link` attribute on an empty extern block. You can use +this to satisfy the linking requirements of extern blocks elsewhere in your code +(including upstream crates) instead of adding the attribute to each extern block. diff --git a/src/doc/reference/src/memory-model.md b/src/doc/reference/src/memory-model.md index 2798b0d165f..aa57ae6ae9b 100644 --- a/src/doc/reference/src/memory-model.md +++ b/src/doc/reference/src/memory-model.md @@ -8,17 +8,3 @@ discipline, exist in the standard library. Allocations in the stack consist of *variables*, and allocations in the heap consist of *boxes*. - -## Memory allocation and lifetime - -The _items_ of a program are those functions, modules and types that have their -value calculated at compile-time and stored uniquely in the memory image of the -rust process. Items are neither dynamically allocated nor freed. - -The _heap_ is a general term that describes boxes. The lifetime of an -allocation in the heap depends on the lifetime of the box values pointing to -it. Since box values may themselves be passed in and out of frames, or stored -in the heap, heap allocations may outlive the frame they are allocated within. -An allocation in the heap is guaranteed to reside at a single location in the -heap for the whole lifetime of the allocation - it will never be relocated as -a result of moving a box value. diff --git a/src/doc/reference/src/tokens.md b/src/doc/reference/src/tokens.md index ae4007b0c99..5a45a2a150b 100644 --- a/src/doc/reference/src/tokens.md +++ b/src/doc/reference/src/tokens.md @@ -303,3 +303,14 @@ The representation semantics of floating-point numbers are described in ### Boolean literals The two values of the boolean type are written `true` and `false`. + +## Symbols + +Symbols are a general class of printable [tokens](#tokens) that play structural +roles in a variety of grammar productions. They are a +set of remaining miscellaneous printable tokens that do not +otherwise appear as [unary operators](#unary-operator-expressions), [binary +operators](#binary-operator-expressions), or [keywords][keywords]. +They are catalogued in [the Symbols section][symbols] of the Grammar document. + +[symbols]: grammar.html#symbols diff --git a/src/doc/reference/src/unsafety.md b/src/doc/reference/src/unsafety.md index f4a9a1d1292..72ae1c725ed 100644 --- a/src/doc/reference/src/unsafety.md +++ b/src/doc/reference/src/unsafety.md @@ -9,32 +9,3 @@ Rust: - Dereferencing a [raw pointer](#pointer-types). - Reading or writing a [mutable static variable](#mutable-statics). - Calling an unsafe function (including an intrinsic or foreign function). - -## Unsafe functions - -Unsafe functions are functions that are not safe in all contexts and/or for all -possible inputs. Such a function must be prefixed with the keyword `unsafe` and -can only be called from an `unsafe` block or another `unsafe` function. - -## Unsafe blocks - -A block of code can be prefixed with the `unsafe` keyword, to permit calling -`unsafe` functions or dereferencing raw pointers within a safe function. - -When a programmer has sufficient conviction that a sequence of potentially -unsafe operations is actually safe, they can encapsulate that sequence (taken -as a whole) within an `unsafe` block. The compiler will consider uses of such -code safe, in the surrounding context. - -Unsafe blocks are used to wrap foreign libraries, make direct use of hardware -or implement features not directly present in the language. For example, Rust -provides the language features necessary to implement memory-safe concurrency -in the language but the implementation of threads and message passing is in the -standard library. - -Rust's type system is a conservative approximation of the dynamic safety -requirements, so in some cases there is a performance cost to using safe code. -For example, a doubly-linked list is not a tree structure and can only be -represented with reference-counted pointers in safe code. By using `unsafe` -blocks to represent the reverse links as raw pointers, it can be implemented -with only boxes.