Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Iterator::all return true for an empty iterator?

Tags:

rust

The following code

fn main() {
    {
        let a: Vec<i32> = vec![1, 2, 3, 4];
        print!("{}\n", a.into_iter().all(|x| x > 1));
    }
    {
        let a: Vec<i32> = vec![];
        print!("{}\n", a.into_iter().all(|x| x > 1));
    }
}

gives me the output

false
true

Surprisingly, a.into_iter().all(|x| x > 1) returned true when a is empty.

Looking at the docs for Iterator::all, I see that it is explicitly stated:

An empty iterator returns true.

Why was it chosen to be this way?

like image 317
Malice Avatar asked Jan 14 '18 09:01

Malice


People also ask

Why does all return true?

all() Return True if all elements of the iterable are true. If the iterable is empty, it return True. This is how I think about the any() and all() functions: any() is like evaluating multiple "or" statements.

How do I check if an iterator is empty in Python?

The best way to do that is with a peekable from more_itertools . from more_itertools import peekable iterator = peekable(iterator) if iterator: # Iterator is non-empty. else: # Iterator is empty.

Why all is true in Python?

The Python all() function returns true if all the elements of a given iterable (List, Dictionary, Tuple, set, etc.) are True otherwise it returns False. It also returns True if the iterable object is empty.


2 Answers

This is the typical convention of the all function in pretty much all programming languages, except those that get it wrong. Conversely, any returns false for empty sequences.

The reason is that it is more useful for typical scenarios. If you have a list of requirements and a value must fulfill all of these to pass through a filter. If your list is actually empty, should the value get through? The answer that usually makes the most sense is yes. Therefore, conditions.all(|value| condition.fulfilled(value)) returns true for the empty list.

It is also a natural consequence of the reformulation of the all definition as, "no item is false", and the default if you implement all in the intuitive way:

fn all<F>(&mut self, f: F) -> bool
where
    F: FnMut(Self::Item) -> bool,
{
    for v in self {
        if !f(v) {
            return false;
        }
    }
    return true;
}

There might even be a basis in mathematics for this, but I couldn't find something quickly.

like image 70
Sebastian Redl Avatar answered Sep 22 '22 16:09

Sebastian Redl


If you are interested in the mathematical basis, here is a short proof:

The statement A => B (A implies B) is logically equivalent to !A | B (not A or B).

The statement S: for each x in X, P(x) is true (where P is a predicate) is a shorthand for for each x: x in X implies P(X) is true.

This statement is hence equivalent to: For each x: P(x) is true or x is not in X

If X is empty, the statement x is not in X is always true so the statement S is true.

like image 32
Guillaume Gris Avatar answered Sep 23 '22 16:09

Guillaume Gris