Problem in storing function (with generic arguments )


#1
  struct New {num: i32 }
  struct ComplexThing <A>   //( L1)
  {   
  calls:  Box<FnMut(&A)+Send+Sync>,
  }
 trait newstrait {
 fn display(&self);
} 
impl newstrait for New {
fn display(&self){println!("new's num value : {}",self.num);}
}
impl newstrait for i32{
fn display(&self){println!("number  : {}",self);}
}
fn  printline<A:newstrait>(p: &A){
 p.display();
}

fn main(){    
let mut vec = Arc::new(Mutex::new(vec![ComplexThing{calls: Box::new(printline)}]));
let mut len; 
{
 let mut vec = vec.lock().unwrap();
 vec.push(ComplexThing{calls: Box::new(printline)}); //storing function in vector
 len = vec.len();
 }  
 for i in 0..len{
 thread::spawn(move||{
 let vec = vec.clone();
 let mut vec= vec.lock().unwrap();
 let ref mut elem =vec[i].calls;                
 if i!=1{
 elem(&New{num:1080}); //calling stored function with instance of structure New as argument ( L2 )     
 }else{
 let num = 434;
 elem(&num);   //calling stored function with i32  as an argument (L3)
 }  
 });           
 } 
 }

It is initialising generic type (A) at L1 with the type of arguments which are sent first and giving error on L3

function_structure2.rs:33:11: 33:15 error: mismatched types:
expected &new,
found &_
(expected struct new,
found integral variable) [E0308]

function_structure2.rs:33 elem(&num);

I read from (https://gist.github.com/Kimundi/8391398) that rust makes copies of function which takes generic arguments for each type at compile time .
If a generic type is initialised with with the type of arguments which are sent first ,then how to overcome this???


#2

https://is.gd/G6EeEh – reformatted


#3

So playing around with this I found that when I declared the vec type:

let mut vec : Arc<Mutex<Vec<ComplexThing>>> = Arc::new(Mutex::new(vec![ComplexThing { calls: Box::new(printline) }]));

I get the error:

<anon>:28:33: 28:45 error: wrong number of type arguments: expected 1, found 0 [E0243]
<anon>:28     let mut vec : Arc<Mutex<Vec<ComplexThing>>> = Arc::new(Mutex::new(vec![ComplexThing { calls: Box::new(printline) }]));

Which hints at what is going on. Without the declaration the compiler is seeing the first call to ComplexThing and saying “Oh A is of type struct New” so when you try calling it with an i32, it starts complaining.

Unfortunately I don’t know how to move forward from that, when I do:

let mut vec : Arc<Mutex<Vec<ComplexThing<newstrait>>>> = Arc::new(Mutex::new(vec![ComplexThing { calls: Box::new(printline) }]));

I get:

<anon>:28:19: 28:59 error: the trait bound `newstrait: std::marker::Sized` is not satisfied [E0277]
<anon>:28     let mut vec : Arc<Mutex<Vec<ComplexThing<newstrait>>>> = Arc::new(Mutex::new(vec![ComplexThing { calls: Box::new(printline) }]));

Oh here is the code formatted nicely for anyone else that wants to look:

use std::sync::{Arc, Mutex};
use std::thread;

struct New {
    num: i32,
}
struct ComplexThing<A> {
    calls: Box<FnMut(&A) + Send + Sync>,
}
trait newstrait {
    fn display(&self);
}
impl newstrait for New {
    fn display(&self) {
        println!("new's num value : {}", self.num);
    }
}
impl newstrait for i32 {
    fn display(&self) {
        println!("number  : {}", self);
    }
}
fn printline<A: newstrait>(p: &A) {
    p.display();
}

fn main() {
    let mut vec : Arc<Mutex<Vec<ComplexThing<newstrait>>>> = Arc::new(Mutex::new(vec![ComplexThing { calls: Box::new(printline) }]));
    let mut len;
    {
        let mut vec = vec.lock().unwrap();
        vec.push(ComplexThing { calls: Box::new(printline) }); //storing function in vector
        len = vec.len();
    }
    for i in 0..len {
        let vec = vec.clone();
        
        thread::spawn(move || {
            
            let mut vec = vec.lock().unwrap();
            let ref mut elem = vec[i].calls;
            if i != 1 {
                let num : i32 = 434;
                elem(&num);   //calling stored function with i32  as an argument (L3)
            } 
            else {
                elem(&New { num: 1080 }); //calling stored function with instance of structure New as argument ( L2 )
            }
        });
    }
}

#4

I got it working but I’m not sure if the results are going to work for you…

use std::sync::{Arc, Mutex};
use std::thread;

struct New {
    num: i32,
}
struct ComplexThing {
    calls: Box<FnMut(&newstrait) + Send + Sync>,
}
trait newstrait {
    fn display(&self);
}
impl newstrait for New {
    fn display(&self) {
        println!("new's num value : {}", self.num);
    }
}
impl newstrait for i32 {
    fn display(&self) {
        println!("number  : {}", self);
    }
}
fn printline(p: &newstrait) {
    p.display();
}

fn main() {
    let mut vec : Arc<Mutex<Vec<ComplexThing>>> = Arc::new(Mutex::new(vec![ComplexThing { calls: Box::new(printline) }]));
    let mut len;
    {
        let mut vec = vec.lock().unwrap();
        vec.push(ComplexThing { calls: Box::new(printline) }); //storing function in vector
        len = vec.len();
    }
    for i in 0..len {
        let vec = vec.clone();
        
        thread::spawn(move || {
            
            let mut vec = vec.lock().unwrap();
            let ref mut elem = vec[i].calls;
            if i != 1 {
                let num : i32 = 434;
                elem(&num);   //calling stored function with i32  as an argument (L3)
            } 
            else {
                elem(&New { num: 1080 }); //calling stored function with instance of structure New as argument ( L2 )
            }
        });
    }
}

I had to change ComplexThing::calls so that it took a &newstrait instead of a generic so it could be properly sized, I guess with the generic it couldn’t guarantee the size of the structure.

I also had to change the signature of printline to take a &newstrait, otherwise the compiler couldn’t guarantee it’s lifetime. I suspect it because when printline uses a generic there end up being multiple implementations of the function, one for each data type passed in. By changing it to take the trait there ends up only 1 implementation…


#5

yeah! it worked @pixel


#6

I must say, @anil1596 you’re doing something very strange.


#7

FYI,

  1. You aren’t getting any parallelism here.
  2. The program will exit before the threads finish executing.