Communicate purpose.

And let compilers do the rest.

Recently I’ve been exploring Rust Clippy lints and started thinking about len zero lint which

Checks for getting the length of something via .len() just to compare to zero, and suggests using .is_empty() where applicable.

In addition to communicating an actual intent, there is another, performance related reason -

Some structures can answer .is_empty() much faster than calculating their length. So it is good to get into the habit of using .is_empty(), and having it is cheap.

This got me thinking about a ways to check if a string is empty:

  1. s == ““

  2. s.is_empty()

  3. s.len() == 0

Depending on the context, each of these options may be chosen for looking most natural, but is there some objective reason, like performance? Let’s put this test:

but the results do not suggest a clear winner:

So to pick a winner, I’ve decided to take a look at the generated assembly for these functions and since in Rust str and String are very different, let’s check them out separately. For &str:

generated code looks identical for all 3 versions:

It simply checks if the length of the character array, passed via %rsi, basically doing s.len() == 0.

For String

the generated code is a little more involved but is still identical for all 3 versions:

The extra complexity comes from the fact that String is represented as

and Vec in turn is represented as

so to get to len we need to skip the buf.

This is great news, since we can just focus on writing code that communicates its intent the best and let the compiler pick the most performant way to back it up.

P.S.: the same holds true for Go’s implementation:

are both translated into