You don't use bounds in the struct, you put them in the impl. So you would instead say
struct LCD<S> { spi: S, ... } and then: impl<S: SPI> LCD<S> { ... } On Tue, Apr 8, 2014 at 1:23 PM, Vladimir Pouzanov <farcal...@gmail.com> wrote: > I might have found an unsupported case. > > Consider the following: > > trait SPI { ... } > > struct McuSPI; > impl SPI for McuSPI { ... } > > struct LCD { > spi: &SPI, > ... > } > > This code results in a dynamic dispatch to SPI, as "trait bounds are not > allowed in structure definitions". Is it in any way possible to use static > dispatch from LCD to SPI given the exact implementations are known at > compile time? > > > On Thu, Apr 3, 2014 at 2:46 AM, Ashish Myles <marci...@gmail.com> wrote: >> >> And just in case there is a confusion (as I have noticed others to >> have), it might help to see a specific example comparing static >> dispatch with dynamic. >> >> // This is a single function for all types implementing the LCD Trait. >> fn foo(x : &LCD) { // x's type is &LCD rather than the actual type of >> the object being passed in >> x.line(....); // dynamic dispatch >> } >> >> // Like C++ templates, this generates a function for each type T that >> implements LCD. >> fn foo<T : LCD>(x : &T) { // x's type is &T rather than &LCD >> x.line(....); // static dispatch based on type T known at compile-time >> } >> >> On Wed, Apr 2, 2014 at 8:32 AM, Daniel Micay <danielmi...@gmail.com> >> wrote: >> > On 02/04/14 06:25 AM, Vladimir Pouzanov wrote: >> >> If I get it right, calls to traits are resolved in runtime (so, traits >> >> are kind of similar to C++ virtual methods). >> > >> > All method calls on regular types are resolved via static dispatch, >> > whether or not they come from a trait. For example, consider a generic >> > function like the following: >> > >> > fn min<T: TotalOrd>(a: T, b: T) -> T { >> > if a < b { a } else { b } >> > } >> > >> > This function performs a *static* call of the `lt` method defined on the >> > `Ord` trait that `TotalOrd` inherits from. Generics are fully expanded >> > at compile-time just as C++ templates are. >> > >> > Rust also allows using traits as boxed objects, but this is an entirely >> > transparent choice. They're almost always used for static dispatch via >> > trait bounds on generics, or simply outside of generics. >> > >> >> What I'm proposing here is a compile-time approach. >> >> >> >> Let's say we have the following trait: >> >> >> >> pub trait LCD { >> >> fn line(&mut self, x0_b: i32, y0_b: i32, x1: i32, y1: i32, color: >> >> u8); >> >> fn rect(&mut self, x0: i32, y0: i32, x1: i32, y1: i32, color: u8); >> >> fn fillrect(&mut self, x0_b: i32, y0_b: i32, x1_b: i32, y1_b: i32, >> >> color: u8); >> >> fn putc(&mut self, value: char); >> >> fn puts(&mut self, s: &str); >> >> >> >> fn flush(&self); >> >> fn clear(&mut self); >> >> } >> >> >> >> which defined a LED screen. There are two structs implementing it: >> >> C12832 and ILI9341 (two different lcd controllers). >> >> >> >> So I want my app to print hello world on lcd, I write the following >> >> code: >> >> >> >> let mut lcd = lcd_c12832::C12832::new(spi); >> >> let mut l: &mut lcd::LCD = lcd as &mut lcd::LCD; >> >> l.puts("hello, world"); >> >> >> >> Which results in a runtime dispatch, a slower and bigger code than the >> >> one I'd have without a trait. >> > >> > You can call methods defined on a trait without boxing the object as a >> > trait object. The ability to perform dynamic dispatch via a trait object >> > is totally optional. The methods can also be called directly, including >> > inside a generic function by specifying the trait as a type parameter >> > bound. You can simply call the `puts` method directly on the `lcd` >> > object without a cast. >> > >> >> A second problem is there is no easy way to write unified code that >> >> supports both the lcds based on passed in --cfg, as I can't >> >> apply #[cfg(lcd_c12832)] to a chunk of code in fn, and it's kind of >> >> problematic to return a &LCD out from it given that there is no heap >> >> and >> >> no analog of placement new from C++. >> > >> > Rust supports generic functions, and you can write code supporting both >> > types by making it generic. The choice between static dispatch and >> > dynamic dispatch is entirely up to you in the current system. >> > >> >> Proposed binding concept solves those two problems: >> >> >> >> #[cfg(lcd_c12832)] >> >> let Binding: binding { >> >> let lcd: &lcd_c12832::C12832; >> >> let main: &Main; >> >> >> >> bind main.lcd = lcd; >> >> } >> >> >> >> at this point of time compiler can be sure about what struct is >> >> implementing LCD trait for main.lcd and can bind the function bodies as >> >> compile time, inlining them if applicable. >> >> >> >> This also might be something that is already implemented, please >> >> advice. >> >> The goal here is to minimise runtime code being executed and its size. >> > >> > >> > >> > _______________________________________________ >> > Rust-dev mailing list >> > Rust-dev@mozilla.org >> > https://mail.mozilla.org/listinfo/rust-dev >> > > > > > > -- > Sincerely, > Vladimir "Farcaller" Pouzanov > http://farcaller.net/ > > _______________________________________________ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > -- http://octayn.net/ _______________________________________________ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev