Default arguments for functions in Rust using macros

macro macro_rules! expr

Unlike Python and several other programming languages, Rust does not allow setting default values to function parameters. Luckily with a little bit of macro-writing we can imitate it.

Here is the whole example

examples/default-arguments/src/main.rs

fn prompt(text: &str, count: u8) {
    println!("prompt '{}' {} times", text, count);
}

macro_rules! prompt {
    ($text: expr, $count: expr) => {
        prompt($text, $count);
    };

    ($text: expr) => {
        prompt($text, 5);
    };
}

fn main() {
    prompt("What is your secret?", 3);

    prompt!("Still with me?", 4);
    prompt!("What is the default?");
}

When we run this we get the following output:

prompt 'What is your secret?' 3 times
prompt 'Still with me?' 4 times
prompt 'What is the default?' 5 times

Explanation

fn prompt(text: &str, count: u8) {
    println!("prompt '{}' {} times", text, count);
}

We have a function that accepts two parameters. A text and a number. If really implemented it I'd have ask the user with the prompt up to count times to answer the question, but we are not here for that.

We would like to have a default value for the count parameter, but Rust does not have that feature.

Use of the function

In the main function above you can see how can we use the function:

prompt("What is your secret?", 3);

Use of the macro

You can also see that we can use the prompt! macro both with and without the 2nd argument.

prompt!("Still with me?", 4);
prompt!("What is the default?");

Write a macro

macro_rules! prompt {
    ($text: expr, $count: expr) => {
        prompt($text, $count);
    };

    ($text: expr) => {
        prompt($text, 5);
    };
}

The line macro_rules! prompt means that our new macro will be called prompt and we will be able to use it as prompt!. That exclamation mark at the end of the name indicates that this is a macro. This is also good, because this way we can use the same name as our function.

Inside the macro definition there are two rules.

The first rule expects 2 expressions that will be called $text and $count. We could really call them anything, but using the same names as are used in the function seemed to make sense. If the compiler encounters prompt! with two parameters, this rule will be matched and the macro will be replaced by a call to the prompt function passing the two parameters to it.

($text: expr, $count: expr) => {
    prompt($text, $count);
};

The second rule expects only one parameter we called $text and then replaces the macro with a call to the prompt function with the parameter we received and the number 5 which is now the default value of the count parameter.

($text: expr) => {
    prompt($text, 5);
};

Conclusion

Macros can be really simple and useful.

Author

Gabor Szabo (szabgab)

Gabor Szabo, the author of the Rust Maven web site maintains several Open source projects in Rust and while he still feels he has tons of new things to learn about Rust he already offers training courses in Rust and still teaches Python, Perl, git, GitHub, GitLab, CI, and testing.

Gabor Szabo