[rust-dev] Porting some nesC features to rust?

Daniel Micay danielmicay at gmail.com
Wed Apr 2 05:32:44 PDT 2014


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.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: OpenPGP digital signature
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140402/1d7ebaf1/attachment.sig>


More information about the Rust-dev mailing list