How to callback a function implemented within `impl`

Hello,

I am currently implementing an event driven system which will trigger certain registered callback functions upon a timer or socket events. (I know i could've used some available library, but would want to learn how to do it by coding and to gain understanding).

An example of it is shown below, All it tries to do is register a callback of another impl and calls run method of EvtMgr.

But the compiler does not like the way the register is being done. Any help is greatly appreciated.

Thanks,

use std::{thread, time};

pub struct EvtMgr {
    fd : i32,
    callback : fn(fd: i32),
}

fn default_callback(_fd : i32) {
}

impl EvtMgr {
    pub fn new() -> EvtMgr {
        let e = EvtMgr {
            fd : -1,
            callback : default_callback,
        };
        e
    }
    pub fn register_callback(&mut self, callback : fn(fd : i32)) {
        self.callback = callback;
    }
    pub fn run(&mut self) {
        loop {
            self.fd += 1;
            thread::sleep(time::Duration::from_millis(100));
            (self.callback)(self.fd);
        }
    }
}

pub struct SocketEvent {
    fd : i32,
}

impl SocketEvent {
    pub fn new() -> SocketEvent {
        let s = SocketEvent {
            fd : -1,
        };
        s
    }
    pub fn socket_callback(&mut self, fd: i32) {
        println!("data {}", fd);
    }
}

fn main() {
    let mut e = EvtMgr::new();
    let mut s = SocketEvent::new();

    e.register_callback(SocketEvent::socket_callback);
    e.run();
}

And the compiler errors,

   Compiling callbacks v0.1.0 (/home/devnaga/work/rust_manual/code/callbacks)
error[E0308]: mismatched types
  --> src/main.rs:51:25
   |
51 |     e.register_callback(SocketEvent::socket_callback);
   |       ----------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
   |       |
   |       arguments to this function are incorrect
   |
   = note: expected fn pointer `fn(i32)`
                 found fn item `for<'r> fn(&'r mut SocketEvent, i32) {SocketEvent::socket_callback}`
note: associated function defined here
  --> src/main.rs:19:12
   |
19 |     pub fn register_callback(&mut self, callback : fn(fd : i32)) {
   |            ^^^^^^^^^^^^^^^^^            -----------------------

For more information about this error, try `rustc --explain E0308`.
error: could not compile `callbacks` due to previous error

In Rust, what we call "methods" are just syntactic sugar for a function that takes self as its first argument. That means SocketEvent::socket_callback has the type fn(&mut SocketEvent, i32), not fn(i32).

If you passed in a move |fd: i32| s.socket_callback(fd) closure, you'll be able to pass in a callable with the right signature.

However, you also have the problem that a fn(...) function is literally just a pointer to some machine code, so it can't contain any extra state.

Normally you'd accept a generic callable (e.g. impl Fn(i32)) or something that has had its type erased (e.g. Box<dyn Fn(i32)>) instead of a bare function so your callbacks can have state.

7 Likes

Thanks Michael !

I am not sure how to use these anyways, still in very uncharted territory of rust :slight_smile: .

I bookmarked your answer so that i could refer back once i understand better rust.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.