136
var strs = new Collection<string>();
bool b = strs.All(str => str == "ABC");

The code creates an empty collection of string, then tries to determine if all the elements in the collection are "ABC". If you run it, b will be true.

But the collection does not even have any elements in it, let alone any elements that equal to "ABC".

Is this a bug, or is there a reasonable explanation?

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Cui Pengfei 崔鹏飞
  • 8,017
  • 6
  • 46
  • 87
  • 4
    Sounds reasonable to me. Use the `Any()` method in connection with it to return false. – Yuriy Faktorovich Oct 25 '11 at 05:04
  • 3
    This is an interesting question of mathematical logic. You might like to think about the related questions 'what is the sum of an empty sequence of integers?' (which seems obvious) and 'what is the *product* of an enpty sequence of integers?' (less so). – AakashM Oct 25 '11 at 09:55
  • 14
    Anything you could possibly say about all of nothing is always true. If a child never had any vegetables on his plate and says "I ate all my vegetables", it would be a true statement, even though he ate none. Another way of saying it is "Of all the vegetables on my plate, I ate them." It's a true statement, because it's an empty statement devoid of any actual claim, because it applies to nothing. "For every vegetable on my plate, I did a jumping jack." That doesn't assert you did any jumping jacks, it asserts "for each vegetable" you did a jumping jack. So if there are no vegetables... – Triynko Aug 26 '16 at 13:24
  • 2
    Interestingly, this question has twice the number of up votes, 3x the number of up votes on the accepted answer, and way more discussion around it. That argues that this manifestation of the question ended up having more value than the one it duplicates which would suggest a flaw in the policy of closed questions only being visible to privileged users. – Derek Greer Feb 26 '20 at 20:38
  • 2
    @Triynko the intuitive problem comes with something like "If all vegetables on your plate are green, do a jumping jack". If I told you that, would you do a jumping jack if your plate is empty? I wouldn't. All vegetables on my plate are not green if there are no vegetables on my plate. – xr280xr Jul 07 '22 at 19:12

7 Answers7

197

It's certainly not a bug. It's behaving exactly as documented:

true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false.

Now you can argue about whether or not it should work that way (it seems fine to me; every element of the sequence conforms to the predicate) but the very first thing to check before you ask whether something is a bug, is the documentation. (It's the first thing to check as soon as a method behaves in a way other than what you expected.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 68
    Without this property, `!Any(Predicate)` would not be the same as `All(!Predicate)`, which would be *very* unintuitive. – Ani Oct 25 '11 at 16:59
  • 36
    Per another poster I found that this situation is called [vacuous truth](http://en.wikipedia.org/wiki/Vacuous_truth) – Paul Tyng Jan 09 '12 at 16:25
  • 10
    Actually, the top SO link in a search is the first thing I check when a function doesn't behave as I expect. Invariably someone with a huge reputation like Jon Skeet not only finds the pertinent snippet of documentation but also explains why my expectations were wrong to begin with. We're spoiled by SO... – ThisGuy Mar 02 '14 at 05:14
  • 12
    I'm not saying it's a bug, but it is odd. I've got no money in any of my bank accounts, so BankAccounts.All(x=>x.TotalFunds > 1000000) is true??? I'm going home! – EightyOne Unite Jan 13 '15 at 15:31
  • 12
    @Stimul8d: It's only true if you don't have any bank accounts at all (or if you *do* have bank accounts, and all of them have that much in them). – Jon Skeet Jan 13 '15 at 15:59
  • this remark must been written in main description, available from VS. – gdbdable Mar 27 '15 at 12:55
  • 2
    This makes no sense. Given an empty set, how can someone with a straight face say "all" match a condition when in fact "none" of them do... because there are none? To be specific, All and Any are not logical inverses, so !Any(Predicate) should not be the same as All(!Predicate). Suppose you wanted to assert that all of a particular subset of a users permissions met a minimum access level. You could not use "all >= minAccess", because it would return true when no permissions were present. You could also not use "not any < minAccess", because it would also return true for an empty set. – Triynko Sep 03 '15 at 14:53
  • 4
    @Triynko: Basically people understand the words "all" in different ways when it comes to whether or not it matches an empty set. You *assert* that All and Any are not logical inverses, but I view them as such - and clearly so do the LINQ designers. There are times when the current behaviour is a pain, and equally there are times when your proposed behaviour is a pain. – Jon Skeet Sep 03 '15 at 14:56
  • 2
    I disagree. Having "All" and "Any" as logical inverses actually creates this precise issue. First of all, by equating them, you make them redundant. If instead "All" returned "false", as it should, for an empty set, then you would use "All" when a non-empty set is a precondition, and you could use "not any" when it is not a precondition. So my proposed behavior would not a pain, because you'd have an actual alternative method. Currently, if I pass a complex lambda to where... I cannot simply call "All" on it, nor can I call "Not Any". I have to repeat the lambda and call both Any and All. – Triynko Sep 03 '15 at 15:14
  • We almost need an "AnyAndAll" method to account for the non-empty-set precondition. – Triynko Sep 03 '15 at 15:29
  • 1
    @Triynko: There are various things in LINQ which are redundant, but still useful to have for expressivity. We'll have to agree to disagree, but as another data point, `java.util.streams.Stream.allMatch` takes the same approach as LINQ: "If the stream is empty then true is returned and the predicate is not evaluated." But yes, I can see that having another operation would potentially be useful. I'm sure there are ways of achieving it in one pass at the moment (while still achieving the short-circuiting, which is the tricky bit) but they wouldn't be terribly pleasant. – Jon Skeet Sep 03 '15 at 15:49
  • @Triynko: And another couple of data points: Python's `all` built-in: "Return True if all elements of the iterable are true (or if the iterable is empty)." And Ruby's `Enumerable#all`: "Passes each element of the collection to the given block. The method returns true if the block never returns false or nil. If the block is not given, Ruby adds an implicit block of `{ |obj| obj }` which will cause `all?` to return true when none of the collection members are false or nil." So it looks like in LINQ-like APIs, "all" operations returning true for the empty set is the prevalent behaviour. – Jon Skeet Sep 03 '15 at 15:59
  • 2
    Compare the paradox added as a comment on MSDN: All items match a predicate, because no items match the predicate. It is not logical and no habit, not even a law would make it logical. – Gerard Dec 24 '15 at 08:56
  • 1
    @Gerard: I think we'll have to agree to disagree... It makes sense to me. – Jon Skeet Dec 24 '15 at 09:12
  • ...following the trail of comments here... for that "AnyAndAll" that was requested it is simply `strs.FirstOrDefault(str => str != "ABC") == null` or if looking specifically for null itself simply use something along the lines of `strs.DefaultIfEmpty(string.Empty).All(str => str == null)` . As per MSDN remarks: _The FirstOrDefault method does not provide a way to specify a default value. If you want to specify a default value other than default(TSource), use the DefaultIfEmpty(IEnumerable, TSource) method as described in the Example section._ – AnorZaken Jan 24 '16 at 20:02
  • 1
    @AnorZaken: I don't think so. `strs.FirstOrDefault(str => str != "ABC") == null` will still return true for an empty sequence... Using `strs.DefaultIfEmpty().All(str => str == "ABC")` would satisfy what the OP wants. – Jon Skeet Jan 24 '16 at 20:10
  • 1
    @JonSkeet My bad, need more coffe ;) Also here is a simple extension that does what was requested: `public static bool All(this IEnumerable source, Func predicate, bool mustExist) { foreach (var e in source) { if (!predicate(e)) return false; mustExist = false; } return !mustExist; }` – AnorZaken Jan 24 '16 at 20:47
  • @AnorZaken: Code doesn't really work well in comments. I suggest you add an answer. – Jon Skeet Jan 24 '16 at 20:51
  • @JonSkeet I suppose that wouldn't hurt... although OP wasn't the one requesting it, it was requested in these comments, sorry for polluting them... – AnorZaken Jan 24 '16 at 21:04
  • @Ani Your answer deserves more visibility. You could post it as a full answer. I find it the most clear and intuitive answer on this page. – Timo Apr 24 '18 at 09:09
  • @Triynko I dunno if "logical inverse" is the right wording but unless I'm mistaken `Any` and `All` are basically the same as the existential and universal quantifiers in logic, and they are convertible to each other. "for all X, X is P" is true in logic when the set is empty for the same reasons mentioned here, and is logically the same as "there is not any X such that X is not P" – Dave Cousineau Oct 11 '18 at 21:36
21

All requires the predicate to be true for all elements of the sequence. This is explicitly stated in the documentation. It's also the only thing that makes sense if you think of All as being like a logical "and" between the predicate's results for each element. The true you're getting out for the empty sequence is the identity element of the "and" operation. Likewise, the false you get from Any for the empty sequence is the identity for logical "or".

If you think of All as "there are no elements in the sequence that are not", this might make more sense.

neonblitzer
  • 124
  • 1
  • 2
  • 10
Mr. Putty
  • 2,276
  • 1
  • 20
  • 20
  • 6
    "there are no elements in the sequence that are not", this is a good one – Cui Pengfei 崔鹏飞 Oct 25 '11 at 05:12
  • This an intuitive interpretation to make in predicate logic. `for all X, P(X)` and `exists X, ~P(X)` [are logically equivalent](http://en.wikipedia.org/wiki/Universal_quantification#Negation). – Brian Oct 25 '11 at 18:32
  • 2
    This is by far the best answer. When these methods were designed, the mathematical background was considered. Thank you for pointing out to that and not only stating "it's written in the docs" over and over as in the other answers! – florien Jul 08 '19 at 20:05
11

It is true, as nothing (no condition) makes it false.

The docs probably explain it. (Jon Skeet also mentioned something a few years back)

Same goes for Any (the opposite of All) returning false for empty sets.

Edit:

You can imagine All to be implemented semantically the same as:

foreach (var e in elems)
{
  if (!cond(e))
    return false;
}
return true; // no escape from loop
leppie
  • 115,091
  • 17
  • 196
  • 297
7

Most answers here seem to go along the lines of "because that's how is defined". But there is also a logical reason why is defined this way.

When defining a function, you want your function to be as general as possible, such that it can be applied to the largest possible number of cases. Say, for instance, that I want to define the Sum function, which returns the sum of all the numbers in a list. What should it return when the list is empty? If you'd return an arbitrary number x, you'd define the function as the:

  1. Function that returns the sum of all numbers in the given list, or x if the list is empty.

But if x is zero, you can also define it as the

  1. Function that returns x plus the given numbers.

Note that definition 2 implies definition 1, but 1 does not imply 2 when x is not zero, which by itself is enough reason to pick 2 over 1. But also note 2 is more elegant and, in its own right, more general than 1. Is like placing a spotlight farther away so that it lightens a larger area. A lot larger actually. I'm not a mathematician myself but I'm sure they'll find a ton of connections between definition 2 and other mathematical concepts, but not so many related to definition 1 when x is not zero.

In general, you can, and most likely want to return the identity element (the one that leaves the other operand unchanged) whenever you have a function that applies a binary operator over a set of elements and the set is empty. This is the same reason a Product function will return 1 when the list is empty (note that you could just replace "x plus" with "one times" in definition 2). And is the same reason All (which can be thought of as the repeated application of the logical AND operator) will return true when the list is empty (p && true is equivalent to p), and the same reason Any (the OR operator) will return false.

Juan
  • 15,274
  • 23
  • 105
  • 187
  • Indeed. Mathematically speaking, "and" is multiplication: "a and b" is equivalent to "a * b". In this way you can justify the And() behavior with e.g. the zero power rule. – Fax Feb 19 '18 at 08:48
4

The method cycles through all elements until it finds one that does not satisfy the condition, or finds none that fail. If none fail, true is returned.

So, if there are no elements, true is returned (since there were none that failed)

Andrew Barber
  • 39,603
  • 20
  • 94
  • 123
3

Here is an extension that can do what OP wanted to do:

static bool All<T>(this IEnumerable<T> source, Func<T, bool> predicate, bool mustExist)
{
    foreach (var e in source)
    {
        if (!predicate(e))
            return false;
        mustExist = false;
    }
    return !mustExist;
}

...and as others have pointed out already this is not a bug but well-documented intended behavior.

An alternative solution if one does not wish to write a new extension is:

strs.DefaultIfEmpty().All(str => str == "ABC");

PS: The above does not work if looking for the default value itself! (Which for strings would be null.) In such cases it becomes less elegant with something similar to:

strs.DefaultIfEmpty(string.Empty).All(str => str == null);

If you can enumerate more than once the easiest solution is:

strs.All(predicate) && strs.Any();

i.e simply add a check after that there actually were any element.

AnorZaken
  • 1,916
  • 1
  • 22
  • 34
1

Keeping the implementation aside. Does it really matter if it is true? See if you have some code which iterates over the enumerable and executes some code. if All() is true then that code is still not going to run since the enumerable doesn't have any elements in it.

var hungryDogs = Enumerable.Empty<Dog>();
bool allAreHungry = hungryDogs.All(d=>d.Hungry);    
if (allAreHungry)
    foreach (Dog dog in hungryDogs)
         dog.Feed(biscuits); <--- this line will not run anyway.
Muhammad Hasan Khan
  • 34,648
  • 16
  • 88
  • 131
  • 5
    Yes, it _will_ actually matter sometimes. For example if you would like to feed the .First() dog. – Kenneth_hj Jan 13 '14 at 13:41
  • Also if you want to perform some other action. What led me to this question is we have a mobile chat app that needs to know if any agents are available to chat with. If there are no agents, we want to redirect the user to send an email instead. – B2K Aug 18 '22 at 16:37