The `todo` macro in Rust

Hi! I would like to share my thoughts on stabilizing the macro todo! (the issue; it seems that I cannot write comments right there).

In all codebases I’ve seen, TODO is used for saying that something should be done.
For example: click
Basically, when this “something” is done, TODO is supposed to be removed.

By contrast, “not implemented”-like wording is used for saying that something is not done.
For example: click
Here we see a typical example where raise NotImplementedError is not supposed to be removed.

When I saw the issue in TWiR I was 100% sure that it is a very special macro which is intended to replace TODO-comments. The true meaning is a completely new way of using the word “todo” and is not intuitive for me at all. Moreover, if the macro is stabilized, we are going to have two kinds of “todo”: the one I described above (TODO-comments) and the one that is Rust-specific synonym for “unimplemented” (to be honest, I don’t understand why one would treat these words as synonyms).

Considering the profit (it is so little, isn’t it?), I would refrain from adding todo macro to Rust.

cc @withoutboats @stjepang

Your still supposed to (if you like) use comments and even .expect("todo") for cases where you wish code to continue executing. It is a convenient search term, so my preference is against unimplemented.

To me your not-implemented example is wrong. The general rust equivalent is;

assert!(false, "Never supported code path");
unreachable!()

Which is a pain so just use panic!. (Note, unreachable! alone is also wrong.) You are wanting to give the message that it is incorrect to ever call such function. (Same applies to input enum variables where some match variant should never get support.)

The existence of todo! is such that you can create your own semantics for using it instead of unimplemented!.

The suggested pattern from the todo! could be used for code paths that would be implemented in the future and unimplemented! for ones that aren’t planned to be implemented or called, but have to be implemented for an interface.

Another possible convention is to use todo! while working on a PR, and never actually have a todo! on master, only unimplemented!.

It’s mainly available as a shorter version of unimplemented!, that code bases are free to put their own patterns of when to use one or the other.

unreachable!()/unimplemented!() can have a message,eg:

fn silly(){
    unreachable!("This {:?} is debug formatted","nope\n\n\"string\"")
}
fn silly2(){
    unimplemented!("This {:?} is debug formatted","nope\n\n\"string\"")
}
fn main(){
    silly();
    silly2();
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e9c14bc4038856a2311c98116d40ae41

2 Likes

The most important thing, imho, is that there be a lint that warns against todo!s usage, so that a todo! does not accidentally sneak its way into production.

2 Likes

I’m adding another vote to the notion that “todo” and “unimplemented” mean very different things in the codebases I’ve worked in. I’ve seen todo used most often for things you’d like to do, but are not strictly required. Some examples:

TODO: switch this function to use the implementation in library X instead
TODO: memoize this function for better performance

“not implemented” is used as an error state for functionality that is not implemented. I personally don’t mind “not implemented” going to production for some work-in-progress code that is not yet called anyway. Anyone who tries to call it will realize pretty quickly its not implemented.

3 Likes