That isn't always going to mean that Rust code is faster, but for benchmark games like this, when Rust is slower it almost always means that the benchmark is wrong.
That isn't always going to mean that Rust code is faster, but for benchmark games like this, when Rust is slower it almost always means that the benchmark is wrong.
As for dynamic dispatch...does Rust not support it, or is there some language construct that allows solving the problems dynamic dispatch solves without imposing annoying limitations or needless verbosity? And, aren't there fast implementations of dynamic dispatch?
Rust supports dynamic dispatch if you truly need it, but the normal approach is to use trait bounds, which the compiler expands when used. Here's an example:
fn main() {
let r = MemReader::new("hello world\n".as_bytes());
get_line(&r);
}
fn get_line<R: Buffer>(r: &R) -> IoResult<String> {
r.read_line()
}
In this very simple example, the `get_line` function takes any value that implements the `Buffer` trait, which provides the `read_line` method. When `get_line` is called inside of `main`, the compiler creates a special version of `get_line` that takes a `MemReader`, and dispatches to its implementation of `read_line` statically. In practice, this feels a lot like dynamic dispatch, but using trait bounds always results in static dispatch in practice. Also, in this example, the `MemReader` is stack-allocated, and lent to the `get_line` method.In very rare cases, you may want dynamic dispatch. For example, imagine you have an array of Buffers, and want to read a line from each of them. In this case, you use a "trait object" (a `Box<Buffer>`), which moves the object to the heap and allows dynamic dispatch.
In practice, I have written many thousands of lines of production Rust code and have only encountered a need for trait objects a handful of times. This means that idiomatic, normal Rust code is stack-allocated and statically dispatched.
The verbosity of trait bounds has decreased more and more over time, and my favorite proposal (by aturon) for making it pretty close to maximally ergonomic is:
fn main() {
let r = MemReader::new("hello world\n".as_bytes());
get_line(&r);
}
fn get_line(r: &impl Reader) -> IoResult<String> {
r.read_line()
}
I hope this lands as new syntax after 1.0 :)Permalink to the relevant section of the Go source, with descriptive comments: https://github.com/golang/go/blob/04cf881fbea55d5bca584c78b1...