Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does "Sized is not implemented" mean?

Tags:

rust

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<W> where W: Writer {     fn handle(&self, &mut W) -> IoResult<()>; }  impl<W, F> Handler<W> 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>(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)    |             ^ doesn't have a size known at compile-time ... 11 | fn handler<W>(w: &mut W) -> io::Result<()>    |    ------- - required by this bound in `handler`    |    = help: the trait `std::marker::Sized` is not implemented for `dyn std::io::Write`    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> 
like image 544
k-ui Avatar asked Jan 20 '15 11:01

k-ui


1 Answers

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

like image 96
huon Avatar answered Sep 21 '22 00:09

huon