From 8f7c2d518d1892c98d2ef57992a65669834f24e2 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Sat, 17 Jan 2015 17:00:32 +0100 Subject: Replace `be` with `become` As per rust-lang/rfcs#601, replace `be` with `become` as reserved keyword for tail call optimization. --- src/doc/grammar.md | 2 +- src/doc/reference.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/doc') diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 59a1c8f828b..b4e023c2039 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -157,7 +157,7 @@ token : simple_token | ident | literal | symbol | whitespace token ; | | | | | | |----------|----------|----------|----------|--------| -| abstract | alignof | as | be | box | +| abstract | alignof | as | become | box | | break | const | continue | crate | do | | else | enum | extern | false | final | | fn | for | if | impl | in | diff --git a/src/doc/reference.md b/src/doc/reference.md index 64ddb3ffdd3..c83cbbce2b2 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -189,7 +189,7 @@ grammar as double-quoted strings. Other tokens have exact rules given. | | | | | | |----------|----------|----------|----------|---------| -| abstract | alignof | as | be | box | +| abstract | alignof | as | become | box | | break | const | continue | crate | do | | else | enum | extern | false | final | | fn | for | if | impl | in | -- cgit 1.4.1-3-g733a5 From d3c787a94f2b66f337334e71634b1c80a359f0bd Mon Sep 17 00:00:00 2001 From: Thiago Carvalho Date: Fri, 6 Feb 2015 15:36:31 +0100 Subject: Book Compound Data Types update From Issue 21829 clarify equivalency of tuples --- src/doc/trpl/compound-data-types.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/doc') diff --git a/src/doc/trpl/compound-data-types.md b/src/doc/trpl/compound-data-types.md index 901b44661b0..aaa016f5a25 100644 --- a/src/doc/trpl/compound-data-types.md +++ b/src/doc/trpl/compound-data-types.md @@ -72,6 +72,20 @@ if x == y { This will print `no`, because some of the values aren't equal. +Note that the order of the values is considered when checking for equality, +so the following example will also print `no`. + +```rust +let x = (1, 2, 3); +let y = (2, 1, 3); + +if x == y { + println!("yes"); +} else { + println!("no"); +} +``` + One other use of tuples is to return multiple values from a function: ```rust -- cgit 1.4.1-3-g733a5 From 403869471871f7996ac09c7a8a5553d26b1c5d9a Mon Sep 17 00:00:00 2001 From: Caspar Krieger Date: Sat, 7 Feb 2015 22:21:01 +1100 Subject: Link to rustdoc page in the Rust book directly No point sending people to a page which just says "this is now part of the Rust book". --- src/doc/index.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/doc') diff --git a/src/doc/index.md b/src/doc/index.md index 252a3125ebd..a4f79412220 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -59,8 +59,7 @@ tools we have are really nice. [Cargo](http://crates.io) is Rust's package manager, and its website contains lots of good documentation. -[The `rustdoc` manual](rustdoc.html) contains information about Rust's -documentation tool. +[`rustdoc`](book/documentation.html) is used to generate documentation for Rust code. # FAQs -- cgit 1.4.1-3-g733a5 From bb49195d22105e11feffc604a2c25128617816b6 Mon Sep 17 00:00:00 2001 From: Geoffrey Thomas Date: Sat, 7 Feb 2015 19:06:49 -0500 Subject: reference.md: Byte string literals start with a 'b' This was correct in the EBNF, but not in the prose (which seems to have been copied-and-pasted from regular string literals). --- src/doc/reference.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/doc') diff --git a/src/doc/reference.md b/src/doc/reference.md index 9851e1c28fb..26d9c60a614 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -381,11 +381,13 @@ character (`\`), or a single _escape_. It is equivalent to a `u8` unsigned ##### Byte string literals -A _byte string literal_ is a sequence of ASCII characters and _escapes_ -enclosed within two `U+0022` (double-quote) characters, with the exception of -`U+0022` itself, which must be _escaped_ by a preceding `U+005C` character -(`\`), or a _raw byte string literal_. It is equivalent to a `&'static [u8]` -borrowed array of unsigned 8-bit integers. +A non-raw _byte string literal_ is a sequence of ASCII characters and _escapes_, +preceded by the characters `U+0062` (`b`) and `U+0022` (double-quote), and +followed by the character `U+0022`. If the character `U+0022` is present within +the literal, it must be _escaped_ by a preceding `U+005C` (`\`) character. +Alternatively, a byte string literal can be a _raw byte string literal_, defined +below. A byte string literal is equivalent to a `&'static [u8]` borrowed array +of unsigned 8-bit integers. Some additional _escapes_ are available in either byte or non-raw byte string literals. An escape starts with a `U+005C` (`\`) and continues with one of the -- cgit 1.4.1-3-g733a5 From 34afe5e193182a0029abe1ae8258f79f4cd56cd9 Mon Sep 17 00:00:00 2001 From: Alexander Korolkov Date: Thu, 5 Feb 2015 15:04:07 +0300 Subject: Rename Show to Debug, String to Display Update reference.md: - derive() no longer supports Zero trait - derive() now supports Copy trait --- src/doc/reference.md | 4 ++-- src/libcore/any.rs | 2 +- src/libgetopts/lib.rs | 6 +++--- src/librustc/middle/ty.rs | 2 +- src/librustdoc/html/format.rs | 2 +- src/libserialize/json.rs | 4 ++-- src/libstd/old_path/mod.rs | 4 ++-- src/libstd/sys/windows/os.rs | 2 +- src/libsyntax/ast.rs | 1 - 9 files changed, 13 insertions(+), 14 deletions(-) (limited to 'src/doc') diff --git a/src/doc/reference.md b/src/doc/reference.md index 9c8191a386d..999cb217f93 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2354,8 +2354,8 @@ Supported traits for `derive` are: * `FromPrimitive`, to create an instance from a numeric primitive. * `Hash`, to iterate over the bytes in a data type. * `Rand`, to create a random instance of a data type. -* `Show`, to format a value using the `{}` formatter. -* `Zero`, to create a zero instance of a numeric data type. +* `Debug`, to format a value using the `{:?}` formatter. +* `Copy`, for "Plain Old Data" types which can be copied by simply moving bits. ### Compiler Features diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 40c2d82bf4b..462b6771b4a 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -27,7 +27,7 @@ //! # Examples //! //! Consider a situation where we want to log out a value passed to a function. -//! We know the value we're working on implements Show, but we don't know its +//! We know the value we're working on implements Debug, but we don't know its //! concrete type. We want to give special treatment to certain types: in this //! case printing out the length of String values prior to their value. //! We don't know the concrete type of our value at compile time, so we need to diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index 1b30bdf230e..72832cb9466 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -195,7 +195,7 @@ pub struct Matches { } /// The type returned when the command line does not conform to the -/// expected format. Use the `Show` implementation to output detailed +/// expected format. Use the `Debug` implementation to output detailed /// information. #[derive(Clone, PartialEq, Eq, Debug)] pub enum Fail { @@ -545,7 +545,7 @@ impl Fail { /// Convert a `Fail` enum into an error string. #[unstable(feature = "rustc_private")] #[deprecated(since = "1.0.0", - reason = "use `fmt::String` (`{}` format specifier)")] + reason = "use `fmt::Display` (`{}` format specifier)")] pub fn to_err_msg(self) -> String { self.to_string() } @@ -579,7 +579,7 @@ impl fmt::Display for Fail { /// `opt_str`, etc. to interrogate results. /// # Panics /// -/// Returns `Err(Fail)` on failure: use the `Show` implementation of `Fail` to display +/// Returns `Err(Fail)` on failure: use the `Debug` implementation of `Fail` to display /// information about it. pub fn getopts(args: &[String], optgrps: &[OptGroup]) -> Result { let opts: Vec = optgrps.iter().map(|x| x.long_to_short()).collect(); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index b29a23924bb..034dbb4271d 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -70,7 +70,7 @@ use arena::TypedArena; use std::borrow::{BorrowFrom, Cow}; use std::cell::{Cell, RefCell}; use std::cmp; -use std::fmt::{self, Show}; +use std::fmt; use std::hash::{Hash, Writer, SipHasher, Hasher}; use std::mem; use std::ops; diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index cc2cf21095e..e916b63eb8d 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -10,7 +10,7 @@ //! HTML formatting module //! -//! This module contains a large number of `fmt::String` implementations for +//! This module contains a large number of `fmt::Display` implementations for //! various types in `rustdoc::clean`. These implementations all currently //! assume that HTML output is desired, although it may be possible to redesign //! them in the future to instead emit any format desired. diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index b8383577987..daa358647d8 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -1032,7 +1032,7 @@ pub fn as_pretty_json(t: &T) -> AsPrettyJson { impl Json { /// Borrow this json object as a pretty object to generate a pretty - /// representation for it via `Show`. + /// representation for it via `Display`. pub fn pretty(&self) -> PrettyJson { PrettyJson { inner: self } } @@ -3540,7 +3540,7 @@ mod tests { fn test_hashmap_with_enum_key() { use std::collections::HashMap; use json; - #[derive(RustcEncodable, Eq, Hash, PartialEq, RustcDecodable, Show)] + #[derive(RustcEncodable, Eq, Hash, PartialEq, RustcDecodable, Debug)] enum Enum { Foo, #[allow(dead_code)] diff --git a/src/libstd/old_path/mod.rs b/src/libstd/old_path/mod.rs index 0d80258d7e0..17cfe1c8297 100644 --- a/src/libstd/old_path/mod.rs +++ b/src/libstd/old_path/mod.rs @@ -228,7 +228,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe { /// ``` fn into_vec(self) -> Vec; - /// Returns an object that implements `Show` for printing paths + /// Returns an object that implements `Display` for printing paths /// /// # Example /// @@ -244,7 +244,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe { Display{ path: self, filename: false } } - /// Returns an object that implements `Show` for printing filenames + /// Returns an object that implements `Display` for printing filenames /// /// If there is no filename, nothing will be printed. /// diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index d8e3e6981df..7e684c52341 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -191,7 +191,7 @@ impl<'a> Iterator for SplitPaths<'a> { } } -#[derive(Show)] +#[derive(Debug)] pub struct JoinPathsError; pub fn join_paths(paths: I) -> Result diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 71259ff5d9a..5ec87eaf8d1 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -64,7 +64,6 @@ use parse::token; use ptr::P; use std::fmt; -use std::fmt::Show; use std::num::Int; use std::rc::Rc; use serialize::{Encodable, Decodable, Encoder, Decoder}; -- cgit 1.4.1-3-g733a5 From 45f667286134c9d48008969c4e3f4b54d9c1dc22 Mon Sep 17 00:00:00 2001 From: Sean Collins Date: Mon, 9 Feb 2015 15:07:47 -0500 Subject: Make fallback font 'serif', rather than 'sans-serif' fonts --- src/doc/rust.css | 2 +- src/librustdoc/html/static/main.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/doc') diff --git a/src/doc/rust.css b/src/doc/rust.css index 3f59f12e74c..c2a25cd7a58 100644 --- a/src/doc/rust.css +++ b/src/doc/rust.css @@ -58,7 +58,7 @@ body { margin: 0 auto; padding: 0 15px; - font-family: "Source Serif Pro", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-family: "Source Serif Pro", Georgia, Times, "Times New Roman", serif; font-size: 18px; color: #333; line-height: 1.428571429; diff --git a/src/librustdoc/html/static/main.css b/src/librustdoc/html/static/main.css index 46faa3efc34..7267f95b31f 100644 --- a/src/librustdoc/html/static/main.css +++ b/src/librustdoc/html/static/main.css @@ -64,7 +64,7 @@ body { color: #333; - font: 16px/1.4 "Source Serif Pro", "Helvetica Neue", Helvetica, Arial, sans-serif; + font: 16px/1.4 "Source Serif Pro", Georgia, Times, "Times New Roman", serif; margin: 0; position: relative; padding: 10px 15px 20px 15px; -- cgit 1.4.1-3-g733a5 From 1163cef1c43d421c54b97ee266bb4f2ddfe4595c Mon Sep 17 00:00:00 2001 From: Luke Steensen Date: Mon, 9 Feb 2015 15:10:33 -0600 Subject: remove obsolete closure syntax from the guide --- src/doc/trpl/closures.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/doc') diff --git a/src/doc/trpl/closures.md b/src/doc/trpl/closures.md index bfb1494efc7..8cc6be7387c 100644 --- a/src/doc/trpl/closures.md +++ b/src/doc/trpl/closures.md @@ -9,7 +9,7 @@ arguments, really powerful things are possible. Let's make a closure: ```{rust} -let add_one = |&: x| { 1 + x }; +let add_one = |x| { 1 + x }; println!("The sum of 5 plus 1 is {}.", add_one(5)); ``` @@ -21,8 +21,8 @@ binding name and two parentheses, just like we would for a named function. Let's compare syntax. The two are pretty close: ```{rust} -let add_one = |&: x: i32| -> i32 { 1 + x }; -fn add_one (x: i32) -> i32 { 1 + x } +let add_one = |x: i32| -> i32 { 1 + x }; +fn add_one (x: i32) -> i32 { 1 + x } ``` As you may have noticed, closures infer their argument and return types, so you @@ -37,7 +37,7 @@ this: fn main() { let x: i32 = 5; - let printer = |&:| { println!("x is: {}", x); }; + let printer = || { println!("x is: {}", x); }; printer(); // prints "x is: 5" } @@ -53,7 +53,7 @@ defined. The closure borrows any variables it uses, so this will error: fn main() { let mut x: i32 = 5; - let printer = |&:| { println!("x is: {}", x); }; + let printer = || { println!("x is: {}", x); }; x = 6; // error: cannot assign to `x` because it is borrowed } @@ -80,7 +80,7 @@ fn twice i32>(x: i32, f: F) -> i32 { } fn main() { - let square = |&: x: i32| { x * x }; + let square = |x: i32| { x * x }; twice(5, square); // evaluates to 50 } @@ -89,7 +89,7 @@ fn main() { Let's break the example down, starting with `main`: ```{rust} -let square = |&: x: i32| { x * x }; +let square = |x: i32| { x * x }; ``` We've seen this before. We make a closure that takes an integer, and returns @@ -97,7 +97,7 @@ its square. ```{rust} # fn twice i32>(x: i32, f: F) -> i32 { f(x) + f(x) } -# let square = |&: x: i32| { x * x }; +# let square = |x: i32| { x * x }; twice(5, square); // evaluates to 50 ``` @@ -184,8 +184,8 @@ fn compose(x: i32, f: F, g: G) -> i32 fn main() { compose(5, - |&: n: i32| { n + 42 }, - |&: n: i32| { n * 2 }); // evaluates to 94 + |n: i32| { n + 42 }, + |n: i32| { n * 2 }); // evaluates to 94 } ``` -- cgit 1.4.1-3-g733a5 From dbccd70a5736fd2e898b446e6c5f3da5d17538c6 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Sun, 8 Feb 2015 20:15:16 -0500 Subject: Add documentation on trait objects. Largely taken from @huonw's http://huonw.github.io/blog/2015/01/peeking-inside-trait-objects/ Fixes #21707 --- src/doc/trpl/SUMMARY.md | 1 + src/doc/trpl/static-and-dynamic-dispatch.md | 286 ++++++++++++++++++++++++++++ src/doc/trpl/traits.md | 47 +---- 3 files changed, 289 insertions(+), 45 deletions(-) create mode 100644 src/doc/trpl/static-and-dynamic-dispatch.md (limited to 'src/doc') diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 9d65f30e723..bfc1247dc3b 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -27,6 +27,7 @@ * [Iterators](iterators.md) * [Generics](generics.md) * [Traits](traits.md) + * [Static and Dynamic Dispatch](static-and-dynamic-dispatch.md) * [Concurrency](concurrency.md) * [Error Handling](error-handling.md) * [Documentation](documentation.md) diff --git a/src/doc/trpl/static-and-dynamic-dispatch.md b/src/doc/trpl/static-and-dynamic-dispatch.md new file mode 100644 index 00000000000..9421dac7bf6 --- /dev/null +++ b/src/doc/trpl/static-and-dynamic-dispatch.md @@ -0,0 +1,286 @@ +% Static and Dynamic Dispatch + +When code involves polymorphism, there needs to be a mechanism to determine +which specific version is actually run. This is called 'dispatch.' There are +two major forms of dispatch: static dispatch and dynamic dispatch. While Rust +favors static dispatch, it also supports dynamic dispatch through a mechanism +called 'trait objects.' + +## Background + +For the rest of this chapter, we'll need a trait and some implementations. +Let's make a simple one, `Foo`. It has one method that is expected to return a +`String`. + +```rust +trait Foo { + fn method(&self) -> String; +} +``` + +We'll also implement this trait for `u8` and `String`: + +```rust +# trait Foo { fn method(&self) -> String; } +impl Foo for u8 { + fn method(&self) -> String { format!("u8: {}", *self) } +} + +impl Foo for String { + fn method(&self) -> String { format!("string: {}", *self) } +} +``` + + +## Static dispatch + +We can use this trait to perform static dispatch with trait bounds: + +```rust +# trait Foo { fn method(&self) -> String; } +# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } } +# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } } +fn do_something(x: T) { + x.method(); +} + +fn main() { + let x = 5u8; + let y = "Hello".to_string(); + + do_something(x); + do_something(y); +} +``` + +Rust uses 'monomorphization' to perform static dispatch here. This means that +Rust will create a special version of `do_something()` for both `u8` and +`String`, and then replace the call sites with calls to these specialized +functions. In other words, Rust generates something like this: + +```rust +# trait Foo { fn method(&self) -> String; } +# impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } } +# impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } } +fn do_something_u8(x: u8) { + x.method(); +} + +fn do_something_string(x: String) { + x.method(); +} + +fn main() { + let x = 5u8; + let y = "Hello".to_string(); + + do_something_u8(x); + do_something_string(y); +} +``` + +This has some upsides: static dispatching of any method calls, allowing for +inlining and hence usually higher performance. It also has some downsides: +causing code bloat due to many copies of the same function existing in the +binary, one for each type. + +Furthermore, compilers aren’t perfect and may “optimise” code to become slower. +For example, functions inlined too eagerly will bloat the instruction cache +(cache rules everything around us). This is part of the reason that `#[inline]` +and `#[inline(always)]` should be used carefully, and one reason why using a +dynamic dispatch is sometimes more efficient. + +However, the common case is that it is more efficient to use static dispatch, +and one can always have a thin statically-dispatched wrapper function that does +a dynamic, but not vice versa, meaning static calls are more flexible. The +standard library tries to be statically dispatched where possible for this +reason. + +## Dynamic dispatch + +Rust provides dynamic dispatch through a feature called 'trait objects.' Trait +objects, like `&Foo` or `Box`, are normal values that store a value of +*any* type that implements the given trait, where the precise type can only be +known at runtime. The methods of the trait can be called on a trait object via +a special record of function pointers (created and managed by the compiler). + +A function that takes a trait object is not specialised to each of the types +that implements `Foo`: only one copy is generated, often (but not always) +resulting in less code bloat. However, this comes at the cost of requiring +slower virtual function calls, and effectively inhibiting any chance of +inlining and related optimisations from occurring. + +Trait objects are both simple and complicated: their core representation and +layout is quite straight-forward, but there are some curly error messages and +surprising behaviours to discover. + +### Obtaining a trait object + +There's two similar ways to get a trait object value: casts and coercions. If +`T` is a type that implements a trait `Foo` (e.g. `u8` for the `Foo` above), +then the two ways to get a `Foo` trait object out of a pointer to `T` look +like: + +```{rust,ignore} +let ref_to_t: &T = ...; + +// `as` keyword for casting +let cast = ref_to_t as &Foo; + +// using a `&T` in a place that has a known type of `&Foo` will implicitly coerce: +let coerce: &Foo = ref_to_t; + +fn also_coerce(_unused: &Foo) {} +also_coerce(ref_to_t); +``` + +These trait object coercions and casts also work for pointers like `&mut T` to +`&mut Foo` and `Box` to `Box`, but that's all at the moment. Coercions +and casts are identical. + +This operation can be seen as "erasing" the compiler's knowledge about the +specific type of the pointer, and hence trait objects are sometimes referred to +"type erasure". + +### Representation + +Let's start simple, with the runtime representation of a trait object. The +`std::raw` module contains structs with layouts that are the same as the +complicated build-in types, [including trait objects][stdraw]: + +```rust +# mod foo { +pub struct TraitObject { + pub data: *mut (), + pub vtable: *mut (), +} +# } +``` + +[stdraw]: ../std/raw/struct.TraitObject.html + +That is, a trait object like `&Foo` consists of a "data" pointer and a "vtable" +pointer. + +The data pointer addresses the data (of some unknown type `T`) that the trait +object is storing, and the vtable pointer points to the vtable ("virtual method +table") corresponding to the implementation of `Foo` for `T`. + + +A vtable is essentially a struct of function pointers, pointing to the concrete +piece of machine code for each method in the implementation. A method call like +`trait_object.method()` will retrieve the correct pointer out of the vtable and +then do a dynamic call of it. For example: + +```{rust,ignore} +struct FooVtable { + destructor: fn(*mut ()), + size: usize, + align: usize, + method: fn(*const ()) -> String, +} + +// u8: + +fn call_method_on_u8(x: *const ()) -> String { + // the compiler guarantees that this function is only called + // with `x` pointing to a u8 + let byte: &u8 = unsafe { &*(x as *const u8) }; + + byte.method() +} + +static Foo_for_u8_vtable: FooVtable = FooVtable { + destructor: /* compiler magic */, + size: 1, + align: 1, + + // cast to a function pointer + method: call_method_on_u8 as fn(*const ()) -> String, +}; + + +// String: + +fn call_method_on_String(x: *const ()) -> String { + // the compiler guarantees that this function is only called + // with `x` pointing to a String + let string: &String = unsafe { &*(x as *const String) }; + + string.method() +} + +static Foo_for_String_vtable: FooVtable = FooVtable { + destructor: /* compiler magic */, + // values for a 64-bit computer, halve them for 32-bit ones + size: 24, + align: 8, + + method: call_method_on_String as fn(*const ()) -> String, +}; +``` + +The `destructor` field in each vtable points to a function that will clean up +any resources of the vtable's type, for `u8` it is trivial, but for `String` it +will free the memory. This is necessary for owning trait objects like +`Box`, which need to clean-up both the `Box` allocation and as well as the +internal type when they go out of scope. The `size` and `align` fields store +the size of the erased type, and its alignment requirements; these are +essentially unused at the moment since the information is embedded in the +destructor, but will be used in future, as trait objects are progressively made +more flexible. + +Suppose we've got some values that implement `Foo`, the explicit form of +construction and use of `Foo` trait objects might look a bit like (ignoring the +type mismatches: they're all just pointers anyway): + +```{rust,ignore} +let a: String = "foo".to_string(); +let x: u8 = 1; + +// let b: &Foo = &a; +let b = TraitObject { + // store the data + data: &a, + // store the methods + vtable: &Foo_for_String_vtable +}; + +// let y: &Foo = x; +let y = TraitObject { + // store the data + data: &x, + // store the methods + vtable: &Foo_for_u8_vtable +}; + +// b.method(); +(b.vtable.method)(b.data); + +// y.method(); +(y.vtable.method)(y.data); +``` + +If `b` or `y` were owning trait objects (`Box`), there would be a +`(b.vtable.destructor)(b.data)` (respectively `y`) call when they went out of +scope. + +### Why pointers? + +The use of language like "fat pointer" implies that a trait object is +always a pointer of some form, but why? + +Rust does not put things behind a pointer by default, unlike many managed +languages, so types can have different sizes. Knowing the size of the value at +compile time is important for things like passing it as an argument to a +function, moving it about on the stack and allocating (and deallocating) space +on the heap to store it. + +For `Foo`, we would need to have a value that could be at least either a +`String` (24 bytes) or a `u8` (1 byte), as well as any other type for which +dependent crates may implement `Foo` (any number of bytes at all). There's no +way to guarantee that this last point can work if the values are stored without +a pointer, because those other types can be arbitrarily large. + +Putting the value behind a pointer means the size of the value is not relevant +when we are tossing a trait object around, only the size of the pointer itself. diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md index d12480d7dd9..e091878cf86 100644 --- a/src/doc/trpl/traits.md +++ b/src/doc/trpl/traits.md @@ -270,51 +270,8 @@ not, because both the trait and the type aren't in our crate. One last thing about traits: generic functions with a trait bound use *monomorphization* (*mono*: one, *morph*: form), so they are statically -dispatched. What's that mean? Well, let's take a look at `print_area` again: - -```{rust,ignore} -fn print_area(shape: T) { - println!("This shape has an area of {}", shape.area()); -} - -fn main() { - let c = Circle { ... }; - - let s = Square { ... }; - - print_area(c); - print_area(s); -} -``` - -When we use this trait with `Circle` and `Square`, Rust ends up generating -two different functions with the concrete type, and replacing the call sites with -calls to the concrete implementations. In other words, you get something like -this: - -```{rust,ignore} -fn __print_area_circle(shape: Circle) { - println!("This shape has an area of {}", shape.area()); -} - -fn __print_area_square(shape: Square) { - println!("This shape has an area of {}", shape.area()); -} - -fn main() { - let c = Circle { ... }; - - let s = Square { ... }; - - __print_area_circle(c); - __print_area_square(s); -} -``` - -The names don't actually change to this, it's just for illustration. But -as you can see, there's no overhead of deciding which version to call here, -hence *statically dispatched*. The downside is that we have two copies of -the same function, so our binary is a little bit larger. +dispatched. What's that mean? Check out the chapter on [static and dynamic +dispatch](static-and-dynamic-dispatch.html) for more. ## Our `inverse` Example -- cgit 1.4.1-3-g733a5 From b42c559e9f0162e9770631e86fb21995d60d0d09 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 9 Feb 2015 21:57:14 -0500 Subject: Remove bottom from the reference Fixes #20172 --- src/doc/reference.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/doc') diff --git a/src/doc/reference.md b/src/doc/reference.md index 9c8191a386d..c2b381fe5e4 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1253,9 +1253,7 @@ fn my_err(s: &str) -> ! { We call such functions "diverging" because they never return a value to the caller. Every control path in a diverging function must end with a `panic!()` or a call to another diverging function on every control path. The `!` annotation -does *not* denote a type. Rather, the result type of a diverging function is a -special type called ⊥ ("bottom") that unifies with any type. Rust has no -syntax for ⊥. +does *not* denote a type. It might be necessary to declare a diverging function because as mentioned previously, the typechecker checks that every control path in a function ends -- cgit 1.4.1-3-g733a5