Call module function by variable

Hello everybody.

I think my question is already answered in the past for many times and i feed google with the wrong question to find out.

I ask my self how can i call functions by variable name?
For example:

mod my_module;

fn main() {
    let fn_var_name = "my_module_fn";

    my_module::fn_var_name ();
}

My feeling says that it is not possible and will not be supported from Rust for good reasons, but i'm not really sure about it.

Thanks for answer
greetings Marcel :slight_smile:

Yes, this isn't possible and will likely never be supported.

If one has a function name as a String and wants call some appropriate function from it one could put all the functions into a hashmap keyed with Strings. Then look them up by name and call them:

use std::collections::HashMap;

pub fn my_fn_0(x:u8, y:f32) -> String{
    "Hello".to_string()
}

pub fn my_fn_1(x:u8, y:f32) -> String{
    "Bye".to_string()
}

pub fn main() {
    type VoidFnPtr = Box<dyn Fn(u8, f32)->String>;
    let mut functions = HashMap::<String, VoidFnPtr>::new();
    functions.insert("my_fn_0".to_string(), Box::new(my_fn_0));
    functions.insert("my_fn_1".to_string(), Box::new(my_fn_1));

    let res = functions.get("my_fn_0").unwrap()(1, 2.0);
    println!("{}", res);

    let res = functions.get("my_fn_1").unwrap()(1, 2.0);
    println!("{}", res);
}

I guess someone smarter than me could suggest ways to wrap that up somehow to make it easier to use. Perhaps with some macro or other.

3 Likes

Yeah this solution was found every time.

But i think there is no different between calling the function directly or call the mapped function. In both way i have to know about the function inside a module.

Yes of course by calling with a variable is the same, thats true. The different in here is, i can import a module without any extras.

In the end, i think i'm not the right guy that can implement this as an marco or else. When Rust is grouped in ten pieces of knowledge, then i define my self on point one. :smiley:

Ultimately one cannot call any function/method in Rust unless that function/method is already compiled into the executable. Such function/method had a name in the source code, it no longer does in the executable binary[*].

The difference is that the function name string could be coming from some user input, or whatever input, at run time. So stashing them in a hashmap allows one to find them.

I have to ask what is it you actually want to achieve with this?

Me too.

[*] I guess one could compile with debugging symbols still in place in the executable and then have the code inspect the executable file it was run from and find the address of the function one wants to call.

I have start 6 month ago with Rust. Most of my time i work with .Net (VisualBasic and C#) to develop customer requests.

I have created my own personal project to learn and understand Rust better. How it works and what is the dynamic of this language.

Yeah and i think i have to much time and i feel boring since corona and the project called "How to create my own languange with Rust" was born.
Yes the easiest project for beginners. :smiley:

And the finaly answer to your question.
I have a parser module that holds other modules that knows how to handle with the tokens.
For exmaple import_keyword module.

mod import_keyword;

while let Some(token_item) = reader.next(){
    import_keyword::check(&token_item);
}

Since i have write this text, i think i have found a other solution and has become a better understanding of my problem

parser.rs
mod import_keyword;
mod other_keyword;
mod one_more_keyword;

trait CheckToken{
    fn parse_token(token: &str) -> Result<ImportAst, Error>
}

pub struct Parser;
impl Parser{
   pub fn analyze(&mut self){
      while let Some(token_item) = reader.next(){
          let res = import_keyword::Parser.parse_token(&token_item);
		
          // code -> handle res
		
          // let res = other_keyword::Parser.parse_token(&token_item);
          // code -> handle res
		
          // let res = one_more_keyword::Parser.parse_token(&token_item);
          // and so on
      }
   }
}

import_keyword.rs
use crate::parser::CheckToken

pub struct Parser;
impl CheckToken for Parser{
    fn parse_token(token: &str) -> Result<ImportAst, Error>{
        // code to return Result
    }
}

The point is not to have dynamic call, the point is to have a unity call.
And by the way. When i read your solution i have understand, importing a module is not all.

I need to know more details from the module to use it. But i can define the detail by a trait and that is the only point i need to to know about the module.

The rest of the implementation inside the module is internal. The outside dont need to know about it.


At the end of the day i hope i have understand Rust for a better usage and not develop a own language.

I'm not so far ahead of you in Rust experience.

I can't help but think that some unrelated concepts are getting mixed up here.

As far as I can gather you want to be able to call functions/methods that are discovered by your parser by name strings. Think calling a "print" function when the parser comes across "print" statement in the text of the language you are parsing.

All of that can done without any Rust modules. Or at least it could all be in the same module.

It may well be wise to organise your code into multiple Rust modules but that is somewhat orthogonal to the actual problem.

2 Likes

Also, it's probably unnecessary and way too complicated to put every keyword in its own module. Don't bother with that. Create a module for the lexer, one for the parser, and one for the AST nodes. Don't try to make your code look like microservices.

1 Like