HiveBrain v1.2.0
Get Started
← Back to all entries
patternrustMajor

What does "Sized is not implemented" mean?

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
implementeddoesmeannotwhatsized

Problem

I wrote the following code:

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 where W: Writer {
    fn handle(&self, &mut W) -> IoResult;
}

impl Handler for F
where W: Writer, F: Fn(&mut W) -> IoResult {
    fn handle(&self, w: &mut W) -> IoResult { (*self)(w) }
}


And then rustc in my terminal:

$ rustc writer_handler.rs
writer_handler.rs:8:15: 8:43 error: the trait
core::marker::Sized is not implemented for the type std::io::Writer
writer_handler.rs:8 let _ = h.handle(&mut stdio::stdout());
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
writer_handler.rs:8:15: 8:43 error: the trait
core::marker::Sized is not implemented for the type std::io::Writer
writer_handler.rs:8 let _ = h.handle(&mut stdio::stdout());
^~~~~~~~~~~~~~~~~~~~~~~~~~~~


Why is this Writer required to implement Sized? It appears to me that the Sized is not needed. What I should do while keeping trait Handler to have this generic argument?

In Rust 1.0, this similar code produces the same problem:

use std::io::{self, Write};

fn main() {
    handle(&mut io::stdout());
}

fn handle(w: &mut Write) -> io::Result {
    handler(w)
}

fn handler(w: &mut W) -> io::Result
where
    W: Write,
{
    writeln!(w, "foo")
}


With the error:

error[E0277]: the trait bound std::io::Write: std::marker::Sized is not satisfied
--> src/main.rs:8:5
|
8 | handler(w)
| ^^^^^^^
std::io::Write does not have a constant size known at compile-time
|
= help: the trait
std::marker::Sized is not implemented for std::io::Write
= note: required by
handler


Later versions of Rust have the error

error[E0277]: the size for values of type dyn std::io::Write` cannot be known at compilation time
--> src/main.rs:8:13
|
8 | handler(w)
|

Solution

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 Writers, 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.

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 where W: Writer {
    fn handle(&self, &mut W) -> IoResult;
}

impl Handler 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: &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.

Code Snippets

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) }
}
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")
}

Context

Stack Overflow Q#28044231, score: 54

Revisions (0)

No revisions yet.