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 <[email protected]> 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 <[email protected]>
> 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
> > [email protected]
> > https://mail.mozilla.org/listinfo/rust-dev
> >
>
--
Sincerely,
Vladimir "Farcaller" Pouzanov
http://farcaller.net/
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev