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

Reply via email to