Skip to content

Commit 7d2c2db

Browse files
committed
tutorial: Reorder sections on traits
/cc: rust-lang#4217
1 parent 850050b commit 7d2c2db

File tree

1 file changed

+82
-82
lines changed

1 file changed

+82
-82
lines changed

doc/tutorial.md

+82-82
Original file line numberDiff line numberDiff line change
@@ -2092,6 +2092,88 @@ the preferred way to use traits polymorphically.
20922092

20932093
This usage of traits is similar to Haskell type classes.
20942094

2095+
## Trait objects and dynamic method dispatch
2096+
2097+
The above allows us to define functions that polymorphically act on
2098+
values of a single unknown type that conforms to a given trait.
2099+
However, consider this function:
2100+
2101+
~~~~
2102+
# type Circle = int; type Rectangle = int;
2103+
# impl int: Drawable { fn draw() {} }
2104+
# fn new_circle() -> int { 1 }
2105+
trait Drawable { fn draw(); }
2106+
2107+
fn draw_all<T: Drawable>(shapes: ~[T]) {
2108+
for shapes.each |shape| { shape.draw(); }
2109+
}
2110+
# let c: Circle = new_circle();
2111+
# draw_all(~[c]);
2112+
~~~~
2113+
2114+
You can call that on an array of circles, or an array of squares
2115+
(assuming those have suitable `Drawable` traits defined), but not on
2116+
an array containing both circles and squares. When such behavior is
2117+
needed, a trait name can alternately be used as a type, called
2118+
an _object_.
2119+
2120+
~~~~
2121+
# trait Drawable { fn draw(); }
2122+
fn draw_all(shapes: &[@Drawable]) {
2123+
for shapes.each |shape| { shape.draw(); }
2124+
}
2125+
~~~~
2126+
2127+
In this example, there is no type parameter. Instead, the `@Drawable`
2128+
type denotes any managed box value that implements the `Drawable`
2129+
trait. To construct such a value, you use the `as` operator to cast a
2130+
value to an object:
2131+
2132+
~~~~
2133+
# type Circle = int; type Rectangle = bool;
2134+
# trait Drawable { fn draw(); }
2135+
# fn new_circle() -> Circle { 1 }
2136+
# fn new_rectangle() -> Rectangle { true }
2137+
# fn draw_all(shapes: &[@Drawable]) {}
2138+
2139+
impl Circle: Drawable { fn draw() { ... } }
2140+
2141+
impl Rectangle: Drawable { fn draw() { ... } }
2142+
2143+
let c: @Circle = @new_circle();
2144+
let r: @Rectangle = @new_rectangle();
2145+
draw_all([c as @Drawable, r as @Drawable]);
2146+
~~~~
2147+
2148+
We omit the code for `new_circle` and `new_rectangle`; imagine that
2149+
these just return `Circle`s and `Rectangle`s with a default size. Note
2150+
that, like strings and vectors, objects have dynamic size and may
2151+
only be referred to via one of the pointer types.
2152+
Other pointer types work as well.
2153+
Casts to traits may only be done with compatible pointers so,
2154+
for example, an `@Circle` may not be cast to an `~Drawable`.
2155+
2156+
~~~
2157+
# type Circle = int; type Rectangle = int;
2158+
# trait Drawable { fn draw(); }
2159+
# impl int: Drawable { fn draw() {} }
2160+
# fn new_circle() -> int { 1 }
2161+
# fn new_rectangle() -> int { 2 }
2162+
// A managed object
2163+
let boxy: @Drawable = @new_circle() as @Drawable;
2164+
// An owned object
2165+
let owny: ~Drawable = ~new_circle() as ~Drawable;
2166+
// A borrowed object
2167+
let stacky: &Drawable = &new_circle() as &Drawable;
2168+
~~~
2169+
2170+
Method calls to trait types are _dynamically dispatched_. Since the
2171+
compiler doesn't know specifically which functions to call at compile
2172+
time, it uses a lookup table (also known as a vtable or dictionary) to
2173+
select the method to call at runtime.
2174+
2175+
This usage of traits is similar to Java interfaces.
2176+
20952177
## Static methods
20962178

20972179
Traits can define _static_ methods, which don't have an implicit `self` argument.
@@ -2179,88 +2261,6 @@ let nonsense = mycircle.radius() * mycircle.area();
21792261

21802262
> ***Note:*** Trait inheritance does not actually work with objects yet
21812263
2182-
## Trait objects and dynamic method dispatch
2183-
2184-
The above allows us to define functions that polymorphically act on
2185-
values of a single unknown type that conforms to a given trait.
2186-
However, consider this function:
2187-
2188-
~~~~
2189-
# type Circle = int; type Rectangle = int;
2190-
# impl int: Drawable { fn draw() {} }
2191-
# fn new_circle() -> int { 1 }
2192-
trait Drawable { fn draw(); }
2193-
2194-
fn draw_all<T: Drawable>(shapes: ~[T]) {
2195-
for shapes.each |shape| { shape.draw(); }
2196-
}
2197-
# let c: Circle = new_circle();
2198-
# draw_all(~[c]);
2199-
~~~~
2200-
2201-
You can call that on an array of circles, or an array of squares
2202-
(assuming those have suitable `Drawable` traits defined), but not on
2203-
an array containing both circles and squares. When such behavior is
2204-
needed, a trait name can alternately be used as a type, called
2205-
an _object_.
2206-
2207-
~~~~
2208-
# trait Drawable { fn draw(); }
2209-
fn draw_all(shapes: &[@Drawable]) {
2210-
for shapes.each |shape| { shape.draw(); }
2211-
}
2212-
~~~~
2213-
2214-
In this example, there is no type parameter. Instead, the `@Drawable`
2215-
type denotes any managed box value that implements the `Drawable`
2216-
trait. To construct such a value, you use the `as` operator to cast a
2217-
value to an object:
2218-
2219-
~~~~
2220-
# type Circle = int; type Rectangle = bool;
2221-
# trait Drawable { fn draw(); }
2222-
# fn new_circle() -> Circle { 1 }
2223-
# fn new_rectangle() -> Rectangle { true }
2224-
# fn draw_all(shapes: &[@Drawable]) {}
2225-
2226-
impl Circle: Drawable { fn draw() { ... } }
2227-
2228-
impl Rectangle: Drawable { fn draw() { ... } }
2229-
2230-
let c: @Circle = @new_circle();
2231-
let r: @Rectangle = @new_rectangle();
2232-
draw_all([c as @Drawable, r as @Drawable]);
2233-
~~~~
2234-
2235-
We omit the code for `new_circle` and `new_rectangle`; imagine that
2236-
these just return `Circle`s and `Rectangle`s with a default size. Note
2237-
that, like strings and vectors, objects have dynamic size and may
2238-
only be referred to via one of the pointer types.
2239-
Other pointer types work as well.
2240-
Casts to traits may only be done with compatible pointers so,
2241-
for example, an `@Circle` may not be cast to an `~Drawable`.
2242-
2243-
~~~
2244-
# type Circle = int; type Rectangle = int;
2245-
# trait Drawable { fn draw(); }
2246-
# impl int: Drawable { fn draw() {} }
2247-
# fn new_circle() -> int { 1 }
2248-
# fn new_rectangle() -> int { 2 }
2249-
// A managed object
2250-
let boxy: @Drawable = @new_circle() as @Drawable;
2251-
// An owned object
2252-
let owny: ~Drawable = ~new_circle() as ~Drawable;
2253-
// A borrowed object
2254-
let stacky: &Drawable = &new_circle() as &Drawable;
2255-
~~~
2256-
2257-
Method calls to trait types are _dynamically dispatched_. Since the
2258-
compiler doesn't know specifically which functions to call at compile
2259-
time, it uses a lookup table (also known as a vtable or dictionary) to
2260-
select the method to call at runtime.
2261-
2262-
This usage of traits is similar to Java interfaces.
2263-
22642264
# Modules and crates
22652265

22662266
The Rust namespace is arranged in a hierarchy of modules. Each source

0 commit comments

Comments
 (0)