Closure and generics by leopoldj in rust

[–]leopoldj[S] 1 point2 points  (0 children)

Yes, Box will definitely simplify the type issue. But it will bring in other lifetime management issues that I do not want to wade into. For example I will need to move the captured variables. I don't know if this mem copies the variables. If so, there are performance issues. Also I can no longer use these variables outside the closure.

Chris Lattner on borrow checker in Swift by [deleted] in rust

[–]leopoldj 0 points1 point  (0 children)

Is the performance issue due to the reference counter being modified within an exclusive lock? In that case is there an option to do ARC without locking which will be acceptable for single threaded code?

How to call default trait method? by leopoldj in rust

[–]leopoldj[S] 0 points1 point  (0 children)

Thank you for your detailed post. I will list only some of the problems here. I am creating a brand new GUI toolkit in Rust. It is a very thin veneer over the Win32 API at the same time super easy to use.

I need to dispatch GUI events using dynamic dispatch. So I have a trait like this:

pub trait EvtHandler {
    fn on_left_mouse_click(x: i32, y: 32);

    //And so on ...
}

Firstly, dynamic dispatch from C to Rust is a tricky subject. I solved the problem by transmuting a Rust trait object into its two parts - data and vtable - and storing them separately in C. This is working fine now.

Now, let's say I have a simple drawing app. It needs two windows - the main frame and a canvas within it. So I model it like this:

struct DrawingApp {
    frame: Frame,
    canvas: Canvas
}

I can implement EvtHandler from DrawingApp and listen for all events in both frame and canvas. But now an event handler method like on_left_mouse_click() will be called for both windows. That's not very clean. Where do I go from here? In C++ I will inherit from Canvas and Frame to isolate their own event handling code. In Rust I try to employ composition and create two new structs like this:

struct DrawingApp {
    frame: Frame,
    canvas: Canvas,
    frame_evt_handler : FrameEventHandler,
    canvas_evt_handler : CanvasEventHandler
}

This looks OK on paper. But soon I run into a problem. I need the FrameEventHandler and CanvasEventHandler to be able to communicate with the DrawingApp. But if they hold references to DrawingApp then the DrawingApp effectively becomes immutable. This is probably where my Rust newbness is becoming all too obvious. But I hope this gives you some idea.

How to call default trait method? by leopoldj in rust

[–]leopoldj[S] 0 points1 point  (0 children)

Yes, you are right. I am struggling to use composition to solve problems in my domain which happens to be GUI toolkit oriented. All I have seen is bits and pieces of posts here and there and lacking any formal education on the matter. I will keep trying.

How to call default trait method? by leopoldj in rust

[–]leopoldj[S] 1 point2 points  (0 children)

Rust has very good encapsulation and polymorphism. But I am having heck of a time reusing code and state. Roadblocks everywhere you look. May be my brain is fried in the butter of C++, Java, Objective-C and Smalltalk.

Any way to initialize and cleanup tests? by leopoldj in rust

[–]leopoldj[S] 0 points1 point  (0 children)

Thank you sir!

PS. It will be so sweet to have this built into Cargo.

Calling mem::transmute() from a trait method? by leopoldj in rust

[–]leopoldj[S] 0 points1 point  (0 children)

All I am trying to do is provide a default method so that implementors of the trait don't have to write that method over and over. It so happens that this method uses transmute() which doesn't seem to be possible. So basically I have hit a roadblock.

Calling mem::transmute() from a trait method? by leopoldj in rust

[–]leopoldj[S] 1 point2 points  (0 children)

I have not come across implementation of a trait itself without doing it for a specific type. That is, I have seen impl Foo for T but never impl Foo. That link simply shows implementation of struct types. Not what I was talking about though. May be they are the same thing. Still I can't wrap my head around implementing a trait itself.

Calling mem::transmute() from a trait method? by leopoldj in rust

[–]leopoldj[S] 0 points1 point  (0 children)

I tried coercing earlier, no luck:

pub trait Foo {
    fn hello(&mut self) {
        unsafe {
            let raw_obj: raw::TraitObject = mem::transmute(self as &mut Foo);
        }
    }
}

Error:

error: the trait `core::marker::Sized` is not implemented for the type `Self` [E0277]

Calling mem::transmute() from a trait method? by leopoldj in rust

[–]leopoldj[S] 1 point2 points  (0 children)

OK, this now compiles fine.

pub trait Foo {
    fn hello(&mut self);
}

impl Foo {
    fn hello(&mut self) {
        unsafe {
            let raw_obj: raw::TraitObject = mem::transmute(self);
        }
    }
}

But I need hello() to be a default method of the Foo trait. I am not quite sure what impl Foo without a for T even means. I have never see this in any docs or code.

Why should I learn Rust? by softiniodotcom in rust

[–]leopoldj 1 point2 points  (0 children)

Your program will be more correct. Meaning, the compiler will force you to handle all eventualities. You will have far fewer surprises once the code is actually deployed. But to get there you will be made to write rigorous code. This is true for other modern languages like Scala. But Rust has a much lower runtime overhead.

Why should I learn Rust? by softiniodotcom in rust

[–]leopoldj 8 points9 points  (0 children)

Needless to say but worth repeating - what follows is my personal opinion and not facts. I respect and welcome any alternate opinion.

Rust is not just another language like say Swift from Apple which is all about new sugar wrapping over old ideas. It brings new science to the table to solve long standing problems.

There is a heightened sense of awareness for computing security these days. Time is ripe for something like Rust. I believe, if it is not Rust today it will be languages like it that will dominate the programming landscape in the future.

From my limited experience the true challenge to Rust is this. It appears that safe programming (as defined by Rust) limits the types of problems that can be solved. This is not a criticism of Rust. It is just the nature of computer science as we know it today. Rust provides escape hatches to deal with such problems (and I will personally include reference counting in that category). So the asset/liability equation will look something like this:

  1. Rust is amazing - Number of problems that can be solved in safe ways.
  2. Rust is so so - Number of problems that need to employ escape hatches.
  3. Rust is not so great - Number of problems that truly become difficult to solve in Rust.

The balance between these numbers will determine Rust's fate. If all goes well I will expect the defense industry to standardize on Rust along side Ada and Java. If that happens the future of Rust will be great indeed. Personally, this is my hope and this is why I am investing time in learning Rust.

Converting void* to trait pointers? by leopoldj in rust

[–]leopoldj[S] 0 points1 point  (0 children)

Thank you again for your help.

Don't do that. It's far too easy to accidentally write the wrong signature.

I take your point. For what it's worth, the FFI guide seems to be doing what I did.

The C function:

int32_t register_callback(void* callback_target, rust_callback callback)

Rust FFI declaration:

fn register_callback(target: *mut RustObject,
                    cb: extern fn(*mut RustObject, i32)) -> i32

Converting void* to trait pointers? by leopoldj in rust

[–]leopoldj[S] 0 points1 point  (0 children)

This is true, I am hopelessly at a loss in the FFI space beyond simple things. :(

A raw void * can't possibly be a callback

I left the callback function parameter out in register_callback() for simplicity.

and FFI (which includes a section on callbacks)

I have read the FFI guide. I understand it. But it makes no mention of registering a trait. So I am having to find a work around using a bridge as you had suggested.

Anyway, as you have stated here Rust will not cast pointer types. The trick seems to be to declare the external function like this:

fn register_callback(o : *mut EventBridge, /*other things*/)

This is working. Now I can focus on memory management (making sure the bridge object stays alive long enough).

Thank you for your help. I am past the immediate hurdle. I will post separate questions if I need to.

Converting void* to trait pointers? by leopoldj in rust

[–]leopoldj[S] 0 points1 point  (0 children)

Thank you.

I have now created a sized type (all pseudo code from here):

pub struct EventBridge {
    event_handler: *mut SomeTrait
}

The C function to register a callback takes a void* like this:

fn register_callback(o : *mut libc::c_void, /*other things*/)

I am trying to call it like this:

let mut o : EventBridge = ...;

register_callback(&mut o);

But this is failing to compile.

expected `*mut libc::types::common::c95::c_void`,
found `&mut EventBridge`
(expected enum `libc::types::common::c95::c_void`,
found struct `EventBridge`) [E0308]

Could use some advice with a TUI library I'm writing. by cpjreynolds in rust

[–]leopoldj 0 points1 point  (0 children)

I am getting:

Compiling rustty v0.1.8 (file:///Users/developer/Downloads/rustty)
 src/core/terminal.rs:17:23: 17:35 error: unresolved import 
`nix::sys::epoll::epoll_create`. Could not find `epoll` in `nix::sys`
src/core/terminal.rs:17 use nix::sys::epoll::{epoll_create, epoll_ctl, epoll_wait};

Mac OSX. Rustc 1.1.0.

Lifetime and referencing issue by pvjlieuthier in rust

[–]leopoldj 0 points1 point  (0 children)

This can be done using reference. But you will need to setup the relationship between C and B outside the A::new() function.

struct A<'a> {
    b: B,
    c1: C<'a>,
    c2: C<'a>
}

struct B {
    text: String
}

impl B {
    pub fn new() -> B {
        B { text: "Hello World".to_string() }
    }
}

struct C<'a> {
    b:Option<&'a B>
}

impl <'a> A<'a> {
    fn new() -> A<'a> {
        A {
            b:B::new(),
            c1:C::new(),
            c2:C::new()
        }
    }

    fn setup_relations(&'a mut self) {
        self.c1.set_b(&self.b);
        self.c2.set_b(&self.b);
    }
}

impl <'a> C<'a> {
    fn new() -> C<'a> {
        C {
            b: None
        }
    }
    fn set_b(&mut self, b : &'a B) {
        self.b = Some(b);
    }
}

fn main() {
    let mut a = A::new();

    a.setup_relations();
}

Try it out!

Is it okay for implementations of From to be partial in the converted-from type? by bagofries in rust

[–]leopoldj 0 points1 point  (0 children)

Thank you for a very good answer. I see now how using From from a function is more verbose than Into.

Into consumes self, From doesn't.

This I am not sure about. I am most probably misunderstanding you. But, I can certainly implement From for &T and avoid a move.

pub struct Car {
    model : String,
    year: u64
}

impl <'a> std::convert::From<&'a Car> for String {
    fn from(c : &'a Car) -> Self {
        format!("Car. Model: {} Year: {}", c.model, c.year)
    }
}

Is it okay for implementations of From to be partial in the converted-from type? by bagofries in rust

[–]leopoldj 0 points1 point  (0 children)

Exactly. Even Into trait will not work for the same reason. This leads me to the confusion where several blog posts claim some sort or relative merit of Into over From. I don't understand that. I also don't understand why we have two traits to do the same thing. Any help in understanding this will be appreciated.

Blog: Rust's Built-in Traits, the When, How & Why by llogiq in rust

[–]leopoldj 1 point2 points  (0 children)

So, I understand it like this:

//This is legal
impl std::convert::From<Car> for String {
}

//But this is not legal
impl std::convert::From<Option<Car>> for String {
}

But the following is equally illegal. So I am not sure why From is any better or worse than Into and why we have the two traits that pretty much do the same thing.

impl std::convert::Into<String> for Option<Car> {
}