The Sized
trait is rather special, so special that it is a default bound on type parameters in most situations. It represents values that have a fixed size known at compile time, like u8
(1 byte) or &u32
(8 bytes on a platform with 64-bit pointers) etc. These values are flexible: they can be placed on the stack and moved onto the heap, and generally passed around by-value, as the compiler knows how much space it needs where-ever the value goes.
Types that aren't sized are much more restricted, and a value of type Writer
isn't sized: it represents, abstractly, some unspecified type that implements Writer
, with no knowledge of what the actual type is. Since the actual type isn't known, the size can't be known: some large types are Writer
s, some small types are. Writer
is one example of a trait object, which at the moment, can only appear in executed code behind a pointer. Common examples include &Writer
, &mut Writer
, or Box<Writer>
.
This explains why Sized
is the default: it is often what one wants.
In any case, for your code, this is popping up because you're using handle
with h
, which is a Fn(&mut Writer) -> IoResult<()>
. If we match this against the F: Fn(&mut W) -> IoResult<()>
type that Handle
is implemented for we find that W = Writer
, that is, we're trying to use handle
with the trait object &mut Writer
, not a &mut W
for some concrete type W
. This is illegal because the W
parameters in both the trait and the impl are defaulting to have a Sized
bound, if we manually override it with ?Sized
then everything works fine:
use std::io::{IoResult, Writer};
use std::io::stdio;
fn main() {
let h = |&: w: &mut Writer| -> IoResult<()> {
writeln!(w, "foo")
};
let _ = h.handle(&mut stdio::stdout());
}
trait Handler<W: ?Sized> where W: Writer {
fn handle(&self, &mut W) -> IoResult<()>;
}
impl<W: ?Sized, F> Handler<W> for F
where W: Writer, F: Fn(&mut W) -> IoResult<()> {
fn handle(&self, w: &mut W) -> IoResult<()> { (*self)(w) }
}
And for the Rust 1.0 code:
use std::io::{self, Write};
fn main() {
handle(&mut io::stdout());
}
fn handle(w: &mut Write) -> io::Result<()> {
handler(w)
}
fn handler<W: ?Sized>(w: &mut W) -> io::Result<()>
where
W: Write,
{
writeln!(w, "foo")
}
I also wrote a blog post about Sized
and trait objects in general which has a little more detail.