Why are len() and is_empty() not defined in a trait?

Viewed 1936

Most patterns in Rust are captured by traits (Iterator, From, Borrow, etc.).

How come a pattern as pervasive as len/is_empty has no associated trait in the standard library? Would that cause problems which I do not foresee? Was it deemed useless? Or is it only that nobody thought of it (which seems unlikely)?

2 Answers

Was it deemed useless?

I would guess that's the reason.

What could you do with the knowledge that something is empty or has length 15? Pretty much nothing, unless you also have a way to access the elements of the collection for example. The trait that unifies collections is Iterator. In particular an iterator can tell you how many elements its underlying collection has, but it also does a lot more.

Also note that should you need an Empty trait, you can create one and implement it for all standard collections, unlike interfaces in most languages. This is the power of traits. This also means that the standard library doesn't need to provide small utility traits for every single use case, they can be provided by libraries!

Just adding a late but perhaps useful answer here. Depending on what exactly you need, using the slice type might be a good option, rather than specifying a trait. Slices have len(), is_empty(), and other useful methods (full docs here). Consider the following:

use core::fmt::Display;

fn printme<T: Display>(x: &[T]) {
    println!("length: {}, empty: ", x.len());

    for c in x {
        print!("{}, ", c);
    }

    println!("\nDone!");
}

fn main() {
    let s = "This is some string";

    // Vector
    let vv: Vec<char> = s.chars().collect();
    printme(&vv);

    // Array
    let x = [1, 2, 3, 4];
    printme(&x);

    // Empty
    let y:Vec<u8> = Vec::new();
    printme(&y);
}

printme can accept either a vector or an array. Most other things that it accepts will need some massaging.

I think maybe the reason for there being no Length trait is that most functions will either a) work through an iterator without needing to know its length (with Iterator), or b) require len because they do some sort of random element access, in which case a slice would be the best bet. In the first case, knowing length may be helpful to pre-allocate memory of some size, but size_hint takes care of this when used for anything like Vec::with_capacity, or ExactSizeIterator for anything that needs specific allocations. Most other cases would probably need to be collected to a vector at some point within the function, which has its len.

Playground link to my example here: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9a034c2e8b75775449afa110c05858e7

Related