Macro invocation and method syntax


#1

I wonder why macro invocation is not allowed in method syntax i.e like this foo.abc!()

An example(simplified) below shows what I want to do in rust. Any idea how to achieve this in rust with or without macros.

struct Greet;

impl Greet {
  pub fn new () -> Greet {
    Greet
  }
  
  pub fn hello (&self) {
    println! ("Hello");
  }

  pub fn hello_with_msg (&self,s: &str) {
    println! ("{}",s);
  }

}

macro_rules! hello {
  () => {
    hello()
  };

  ($value) => {
    hello_with_msg ($value)
  };
}

fn main () {
  let greet = Greet::new ();

  greet.hello();
  greet.hello_with_msg("Hello, how are you");

  greet.hello!();
  greet.hello!("Hello, how are you");

}

#2

It looks like you’re trying to implement method overloading. There’s a reason why it wasn’t included in Rust. :smile:

The closest you could do is something like this:

macro_rules! call_hello {
    ($greet:expr) => {
        $greet.hello()
    };
    (greet:expr, $message:expr) => {
        $greet.hello_with_msg($message);
    };
}

and then invoke it like so:

call_hello!(Greet::new());
call_hello!(Greet::new(), "Hello, world!");

Again, this isn’t really idiomatic to Rust. Your current hello()/hello_with_msg() is what is preferred, as it more clearly indicates your intent. I’ve personally had method overloading bite me in the butt a few times before, in Java.


#3

Thanks for the code :slight_smile: .

I was exploring terminal setting in linux , so basically I was looking for some kind abstract getter and setter with same name and I guess overloading is one way to achieve it.

I guess there must be a good reason for it , so be it :smile:

I think I can manage without overloading and still use method syntax with same name, but need to use extra structure.

So to set terminal local flag setting I would use

 term.set_lflag().echo(true).icanon(false).tcsanow()

Here set_lflag() produces some type which implement setter for local flags via method calls.

And now to get terminal local flag terminal setting I would now use

let enabled = term.get_lflag().icanon();

Here again get_lflag() produces some type which implement getter for local flags via method calls with same name as in setter .

This increases the code bloat and maybe sucks a little :blush: but can be generated via macros. I am not sure if this is the correct design , but surely makes terminal interface looks elegant for use in client application.


#4

That particular design would also be rather limiting; the macro has no access to the subject of the call. For comparison, here’s a draft pre-RFC I wrote on the subject. So I’d say there’s interest in it from some quarters, but whether it happens or not (shrugs).