How to Write Better Compilation Error Message In Rust

struct
Reading Time: 3 minutes

While exploring Rust’s standard libraries, I came across a beautiful feature of RUST compile_error. However this feature is useful for only specific use cases,

for example:- when you are defining macro_rules! or conditional compilation strategy.

Let’s see both use cases, one by one.

1) macro_rules

macro is a very powerful feature in Rust. We use it for metaprogramming for reducing the amount of code. We all know that macro definitions are hard to understand and compilation errors in macro are even more difficult to understand for a developer. I won’t get into details of macros in this blog, I would only explain how we can write a better error message so that it would be easy for a developer to understand.

Let’s see an example without compile_error :

macro_rules! area {
    ($a:expr, $b:expr) => {
        $a * $b
    };
}

fn main() {
    println!("Area is {:#?}. ", area!(2, 3, 6))
}

I won’t say this is a good example, this is just to show you how we can use this feature. If you run the above program using `cargo run`. You would see below error message. This message is not very helpful to someone who expected area to be calculated with hight, length and width.

Now let’s implement compile_error feature:

macro_rules! area {
    ($a:expr, $b:expr) => {
        $a * $b
    };
    ($x:expr, $($y:expr),+) => {
        compile_error!(
            "For now, you can only calculate area of rectangle.\
             \
             For example:- area!(2,3)\
             "
        )
    };
}

fn main() {
    println!("Area is {:#?}. ", area!(2, 3, 6))
}

If you run above program, you would see a better compilation error message.

2) conditional compilation

We can also use this feature in conditional compilation. Conditional compilation is compilation implementing methods which allow the compiler to produce differences in the executable program produced and controlled by parameters that are provided during compilation. Rust has a special attribute, #[cfg], which allows you to compile code based on a flag passed to the compiler.

Let’s see an example below:

Define two features in Cargo.toml. I am assuming you are aware with [features] section of Cargo.

[features]
# A feature with no dependencies is used mainly for conditional compilation,
# like `#[cfg(feature = "foo")]`.
foo = []

bar = []
fn main() {
    #[cfg(not(feature = "foo"))]
    compile_error!("Feature foo must be enabled for this crate.");

    #[cfg(not(feature = "bar"))]
    compile_error!("Feature bar must be enabled for this crate.");
}

When you will run this program using cargo run, you would see two compilation error messages.

Now run this program with cargo run --features "foo". When you do this,  it will send the --cfg feature="foo" flag to rustc.

Now you will see only one error message. If you again run by enabling both features using cargo run --features "foo bar". You won’t get any compilation error.

I hope you enjoyed this blog. Thanks for reading !


Knoldus-blog-footer-image

Written by 

Ayush is the Sr. Lead Consultant @ Knoldus Software LLP. In his 10 years of experience he has become a developer with proven experience in architecting and developing web applications. Ayush has a Masters in Computer Application from U.P. Technical University, Ayush is a strong-willed and self-motivated professional who takes deep care in adhering to quality norms within projects. He is capable of managing challenging projects with remarkable deadline sensitivity without compromising code quality.

Knoldus Pune Careers - Hiring Freshers

Get a head start on your career at Knoldus. Join us!