@@ -2092,6 +2092,88 @@ the preferred way to use traits polymorphically.
20922092
20932093This 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
20972179Traits 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
22662266The Rust namespace is arranged in a hierarchy of modules. Each source
0 commit comments