Behavior of all() and any() on empty vectors

This caught me by surprise:

julia> any(x->true, [])
false

julia> all(x->true, [])
true

julia> any(x->false, [])
false

julia> all(x->false, [])
true

This seems like a bug - I think that all should never be true when any is false. But I’m guessing there’s a principled reason for this. Can anyone explain it to me?

1 Like

The key is this that any returns true if there are any true elements. No elements means that there can’t be any true elements, thus it’s always false. Similarly all returns false if there are any false elements. No elements means there can’t be any false elements, thus it’s always true. Both short-circuit upon finding the first “exceptional” value when it knows the result.

Practically, I really like the any behavior but — while I see the motivation and symmetry — I often want all([]) to be false. I often just have to remember to add in the fact that I want !isempty to my predicates that include all.

4 Likes

Yeah, this seems more sensible to me. Logically, it seems like all(f, x) && !any(f, x) should never be true.

This behavior agrees with Matlab, at least.

Yeah, there are two ways to think about these operations. There’s the way we (and Matlab and Numpy) operate:

  • any: true if contains a true, false otherwise
  • all: false if contains a false, true otherwise

They could also potentially be defined by leading with the converse in an alternate universe′:

  • any′: false if only contains falses, true otherwise. Thus: any′([]) == true
  • all′: true if only contains trues, false otherwise. Thus: all′([]) == false

I think colloquially, we tend to think about how things are true (that is, leading with the true if…; the any and all′ definitions), but if the “all” operation is going to short-circuit like any does, then it’s sensible to be defined as all. The docstring could probably be clearer in this regard.

1 Like

With this definition, it’s not obvious to me that any'([]) == true… In a sense, Bool[] contains only false, as it doesn’t contain any trues and can’t contain something else than true or false.

I don’t know if the current definition is “principled”, but it’s consistent with sum and prod: any(a) is equivalent to sum(a) % Bool (think a sum in the 2-element field GF(2)), and all(a) is equivalent to prod(a). An empty sum is usually defined to be the addition identity, i.e. 0 or false in our case, whereas an empty product is defined to be the mutliplication identity, i.e. 1 or true.

1 Like

I would say Bool[] does not contain a single false. Perhaps there’s better verbiage to be used than “only contains”, but it’s tricky to define these without using the words (implicitly or explicitly) themselves. I think you’re implicitly using the "true if" definition here. :slight_smile:

Absolutely! It’s because I can’t really decide if an empty collection contains “only false”… it’s not a clear concept, so for me the closest definition to disambiguate this corner case is the “true if”, while for you it’s the “not empty and contains only false” :slight_smile:

1 Like