.NET's Sometimes Nonsensical Logic
-
Well look I'm not saying there's no good *argument* in favor of `[Empty].All()` returning `true`, and I totally get the programming logic of starting with `true` and breaking if and only if you find a `false`. It's not like the decision is unjustifiable. But I think the "Right Thing" to do here is more than sufficiently debatable that if ever there was a time to throw an exception (which they love to do in countless other contexts) it would be here.
I disagree with throwing an exception for that an empty collection.
-
I disagree with throwing an exception for that an empty collection.
Only because you agree with their logic. Not everyone does. The ambiguity is the issue, not whether you or I agree with the decision.
-
Someone really should start a weekly blog of inane .NET logic when it comes to what it does or does not throw an exception for vs. just behaving according to some default arbitrary choice. Entry #1: On an empty collection, `.Any()`, with our without a condition, always returns `false`, as any sane person would expect. However, `.All(condition)`, on an empty collection, returns `true`. HUH? If I look at an empty room and ask "Are all the people in there aliens?" the answer I expect is apparently YES? If ever there were a situation where a method call is so nonsensical that there is no possible objectively right way to handle that which everyone would agree on (thus justifying an Exception), it's asking about `All` the items in an empty collection. It's tantamount to division by zero. And yet on a `null` collection, even though these are all extension methods and perfectly capable of treating `null` as empty, it throws .NET's all time favorite and #1 most useless exception, `NulLReferenceException`. Clearly the .NET developers' goal is to ruin as many of my days as possible.
In logic,
ALL(P(x))
[would be equivalent to](https://en.wikipedia.org/wiki/First-order\_logic#Provable\_identities)NOT ANY(NOT P(x))
. So if you agree on that[Empty].Any(...)
would always be false, then it logically follows that[Empty].All(...)
would be true. -
Someone really should start a weekly blog of inane .NET logic when it comes to what it does or does not throw an exception for vs. just behaving according to some default arbitrary choice. Entry #1: On an empty collection, `.Any()`, with our without a condition, always returns `false`, as any sane person would expect. However, `.All(condition)`, on an empty collection, returns `true`. HUH? If I look at an empty room and ask "Are all the people in there aliens?" the answer I expect is apparently YES? If ever there were a situation where a method call is so nonsensical that there is no possible objectively right way to handle that which everyone would agree on (thus justifying an Exception), it's asking about `All` the items in an empty collection. It's tantamount to division by zero. And yet on a `null` collection, even though these are all extension methods and perfectly capable of treating `null` as empty, it throws .NET's all time favorite and #1 most useless exception, `NulLReferenceException`. Clearly the .NET developers' goal is to ruin as many of my days as possible.
I agree. I find the behavior of
All()
on an empty collection strange. If I'm told "all the members of a list of integers are greater than zero" I would expectAny(p => p > 0)
on that list to returntrue
. But if the list is empty,Any(p => p > 0)
returnsfalse
. That seems wrong. /raviMy new year resolution: 2048 x 1536 Home | Articles | My .NET bits | Freeware ravib(at)ravib(dot)com
-
In logic,
ALL(P(x))
[would be equivalent to](https://en.wikipedia.org/wiki/First-order\_logic#Provable\_identities)NOT ANY(NOT P(x))
. So if you agree on that[Empty].Any(...)
would always be false, then it logically follows that[Empty].All(...)
would be true. -
In logic,
ALL(P(x))
[would be equivalent to](https://en.wikipedia.org/wiki/First-order\_logic#Provable\_identities)NOT ANY(NOT P(x))
. So if you agree on that[Empty].Any(...)
would always be false, then it logically follows that[Empty].All(...)
would be true.To add to this, what universality (All) is really saying is that "nothing exists that violates this constraint", whereas existentiality (Any) is really saying "at least one thing exists that obeys this constraint." With [].All(constraint), nothing exists to violate the constraint, so All() returns true. With [].Any(constraint), nothing exists to obey the constraint, so Any() returns false.
-
Yes, we have no bananas.... how about malloc( 0 ) not returning NULL.
"A little time, a little trouble, your better day" Badfinger
That was interesting. Apparently that is undefined so implementation dependent. I wonder why. I suspect some memory allocators would have trouble with allocating an empty block so perhaps that is the reason to allow null. What is additionally interesting was that I was thinking it would return just a pointer to the heap block tracker. That is so free still works. But of course it could actually return real space. So for example if the allocator just always sizes up to a block (say 16 bytes) it might be valid space.
-
That was interesting. Apparently that is undefined so implementation dependent. I wonder why. I suspect some memory allocators would have trouble with allocating an empty block so perhaps that is the reason to allow null. What is additionally interesting was that I was thinking it would return just a pointer to the heap block tracker. That is so free still works. But of course it could actually return real space. So for example if the allocator just always sizes up to a block (say 16 bytes) it might be valid space.
I brought it up a while back and there was some back and forth on it. Apparently, malloc( 0 ) not returning NULL is deliberate. Here is what GCC does with some short bit of code printf("Hello world!\n"); printf( "call malloc(0)\n" ); sz = (char*)malloc(ZERO); printf( "Errno %d\n", errno ); if( sz == NULL ) printf( "returned NULL allocated zero bytes\n"); else printf( "NULL not returned from malloc, allocated 8 bytes\n" ); Hello world! call malloc(0) Errno 0 NULL not returned from malloc, allocated 8 bytes Apparently this is allowed by GCC. The argument is that it was successful Haven't tried it in VS.
"A little time, a little trouble, your better day" Badfinger
-
Someone really should start a weekly blog of inane .NET logic when it comes to what it does or does not throw an exception for vs. just behaving according to some default arbitrary choice. Entry #1: On an empty collection, `.Any()`, with our without a condition, always returns `false`, as any sane person would expect. However, `.All(condition)`, on an empty collection, returns `true`. HUH? If I look at an empty room and ask "Are all the people in there aliens?" the answer I expect is apparently YES? If ever there were a situation where a method call is so nonsensical that there is no possible objectively right way to handle that which everyone would agree on (thus justifying an Exception), it's asking about `All` the items in an empty collection. It's tantamount to division by zero. And yet on a `null` collection, even though these are all extension methods and perfectly capable of treating `null` as empty, it throws .NET's all time favorite and #1 most useless exception, `NulLReferenceException`. Clearly the .NET developers' goal is to ruin as many of my days as possible.
I feel what you feel but! If you walk in a room and ask if anyone is there and there is no reply you have to note that down as false. If you walk in a room and ask if all of them are aliens, but no one denies (cause nobody there) you note that down as true. If there is no room you can walk into you can't ask questions in there, hence you trip and fall into the backrooms (nullException) So MS is right, although it seems a bit off.
MessageBox.Show(!string.IsNullOrWhiteSpace(_signature)
? $"This is my signature:{Environment.NewLine}{_signature}": "404-Signature not found"); -
Would you think otherwise if the method were called `Every`?
No. :) Maybe its a mathematical mindset. "Is this condition true for every member of this (empty) set?" has to return
true
, since there are no members of the set where the condition is not true. Similarly, "Is this condition true for any member of this (empty) set?" has to returnfalse
, since there are no members of the set where the condition is true.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Someone really should start a weekly blog of inane .NET logic when it comes to what it does or does not throw an exception for vs. just behaving according to some default arbitrary choice. Entry #1: On an empty collection, `.Any()`, with our without a condition, always returns `false`, as any sane person would expect. However, `.All(condition)`, on an empty collection, returns `true`. HUH? If I look at an empty room and ask "Are all the people in there aliens?" the answer I expect is apparently YES? If ever there were a situation where a method call is so nonsensical that there is no possible objectively right way to handle that which everyone would agree on (thus justifying an Exception), it's asking about `All` the items in an empty collection. It's tantamount to division by zero. And yet on a `null` collection, even though these are all extension methods and perfectly capable of treating `null` as empty, it throws .NET's all time favorite and #1 most useless exception, `NulLReferenceException`. Clearly the .NET developers' goal is to ruin as many of my days as possible.
.NET's behavior is similar to the Principle of explosion It is not a fallacy, it is a matter of "careful what you wish, you just might get it". If you ask for multiple elements to satisfy a condition, you should be aware that you are, in fact, asking 2 questions: 1. I want at least 1 element 2. Each one of them satisfies the criterion. Do not count on the tooth fairy to satisfy your hidden criterion #1, make it explicit instead.
-
No. :) Maybe its a mathematical mindset. "Is this condition true for every member of this (empty) set?" has to return
true
, since there are no members of the set where the condition is not true. Similarly, "Is this condition true for any member of this (empty) set?" has to returnfalse
, since there are no members of the set where the condition is true.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
I don't have a horse in this race, but I agree with your logic.
>64 It’s weird being the same age as old people. Live every day like it is your last; one day, it will be.
-
I can see what you mean, but I can see the logic as well -- so I agree with MS on this. With Any, you begin by setting the result to false, then iterate the tests, if any of the tests is true, you return true -- so no tests yields false. With All, you begin by setting the result to true, then iterate the tests, if any of the tests is false, you return false -- so no tests yields true. Both have a short-circuit feature, which is a good thing. I definitely agree that MS needed to have a more cohesive development team who communicated and decided on things like this.
The trouble is that you're explaining the logic of the implementation, whereas the question concerns the logic of the outcome. The outcomes of .Any() and .All() on empty collections are logically inconsistent. Logically the answer to whether anything in an empty collection or everything in the same collection meet some criterion is "No" in both cases. Similarly a null exception is absurd. My guess is that whoever coded and reviewed one of the two methods didn't first grasp the behaviour of the other. It happens a lot, in my experience.
-
There are certainly some odd decisions in the .NET class libraries. But I don't agree with you on this one. From a purely logical perspective, checking whether all members of an empty set satisfy a particular condition should always return
true
- there are no members which don't satisfy the condition, so returningfalse
would be senseless. If you want an example of a nonsensical decision, look no further than theSystem.Text.Json.JsonElement
'sTryGet...
methods, which will throw an exception if the "JSON type" of the element is wrong. SoTryGetInt64
will returntrue
for{ "id": 42 }
; returnfalse
for{ "id": 3.1415 }
; and throw an exception for{ "id": "42" }
. :wtf: Given the usualTryParse
pattern, you might expect these methods to returnfalse
for any invalid input. But that's not what they do. They returnfalse
for some kinds of invalid input, and throw an exception for other kinds of invalid input.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
So if you asked your sergeant if your platoon was all present and correct when in fact they'd all been blown to smithereens and the platoon was now devoid of soldiers, you would still expect the answer "Yes"?
-
.NET's behavior is similar to the Principle of explosion It is not a fallacy, it is a matter of "careful what you wish, you just might get it". If you ask for multiple elements to satisfy a condition, you should be aware that you are, in fact, asking 2 questions: 1. I want at least 1 element 2. Each one of them satisfies the criterion. Do not count on the tooth fairy to satisfy your hidden criterion #1, make it explicit instead.
I agree - code defensively. Check that the collection has something to interrogate, and if it has, proceed to do so. Otherwise define the behaviour you want if it is empty. Don't be lazy!
-
Someone really should start a weekly blog of inane .NET logic when it comes to what it does or does not throw an exception for vs. just behaving according to some default arbitrary choice. Entry #1: On an empty collection, `.Any()`, with our without a condition, always returns `false`, as any sane person would expect. However, `.All(condition)`, on an empty collection, returns `true`. HUH? If I look at an empty room and ask "Are all the people in there aliens?" the answer I expect is apparently YES? If ever there were a situation where a method call is so nonsensical that there is no possible objectively right way to handle that which everyone would agree on (thus justifying an Exception), it's asking about `All` the items in an empty collection. It's tantamount to division by zero. And yet on a `null` collection, even though these are all extension methods and perfectly capable of treating `null` as empty, it throws .NET's all time favorite and #1 most useless exception, `NulLReferenceException`. Clearly the .NET developers' goal is to ruin as many of my days as possible.
Wikipedias page on Empty set[^] shows the properties of an empty set - which defined this behavior. Personally I would have been very surprised if All() on an empty set would ever return false - as I one or another time managed to get "everything applies to all elements in the empty set" stuck in my head. :D
-
No. :) Maybe its a mathematical mindset. "Is this condition true for every member of this (empty) set?" has to return
true
, since there are no members of the set where the condition is not true. Similarly, "Is this condition true for any member of this (empty) set?" has to returnfalse
, since there are no members of the set where the condition is true.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
You're not wrong. But you're not right either. Maths vs. Words :-D
-
I agree - code defensively. Check that the collection has something to interrogate, and if it has, proceed to do so. Otherwise define the behaviour you want if it is empty. Don't be lazy!
Oh after this episode I no longer use `All`; instead: public static bool AnyAndAll(this IEnumerable source, Func predicate) { if (source == null) return false; bool any = false; foreach (var item in source) { if (!predicate(item)) return false; any = true; } return any; }
-
Someone really should start a weekly blog of inane .NET logic when it comes to what it does or does not throw an exception for vs. just behaving according to some default arbitrary choice. Entry #1: On an empty collection, `.Any()`, with our without a condition, always returns `false`, as any sane person would expect. However, `.All(condition)`, on an empty collection, returns `true`. HUH? If I look at an empty room and ask "Are all the people in there aliens?" the answer I expect is apparently YES? If ever there were a situation where a method call is so nonsensical that there is no possible objectively right way to handle that which everyone would agree on (thus justifying an Exception), it's asking about `All` the items in an empty collection. It's tantamount to division by zero. And yet on a `null` collection, even though these are all extension methods and perfectly capable of treating `null` as empty, it throws .NET's all time favorite and #1 most useless exception, `NulLReferenceException`. Clearly the .NET developers' goal is to ruin as many of my days as possible.
This may be considered a "dumb" response, but why not check for null and if not null, get a count, on your collection before attempting an action that presumes items in the collection?
-
Someone really should start a weekly blog of inane .NET logic when it comes to what it does or does not throw an exception for vs. just behaving according to some default arbitrary choice. Entry #1: On an empty collection, `.Any()`, with our without a condition, always returns `false`, as any sane person would expect. However, `.All(condition)`, on an empty collection, returns `true`. HUH? If I look at an empty room and ask "Are all the people in there aliens?" the answer I expect is apparently YES? If ever there were a situation where a method call is so nonsensical that there is no possible objectively right way to handle that which everyone would agree on (thus justifying an Exception), it's asking about `All` the items in an empty collection. It's tantamount to division by zero. And yet on a `null` collection, even though these are all extension methods and perfectly capable of treating `null` as empty, it throws .NET's all time favorite and #1 most useless exception, `NulLReferenceException`. Clearly the .NET developers' goal is to ruin as many of my days as possible.
I figured I might be in the minority here, but suprised how overwhelmingly folks agree with Microsoft on `[Empty].All() == true`. Mathematically I totally get it. None of the items is false. Fine. But consider a real-world application and what I, as someone giving orders, would expect: Darth Vader is commanding the Imperial fleet and approaching a suspected Rebel base but is uncharacteristically concerned about civilian casualties for once. "Are there any civilian inhabitants of this planet, commander?" "No, Lord Vader," the commander replies. "Good, so they're all rebels?" "Yes, milord." "Sterilize the planet," Vader commands. The fleet spends the next four hours bombarding the planet, burning the entire surface and boiling the oceans, while Vader waits impatiently as he is eager to proceed to the next suspected target. Finally when the carnage is over, Vader asks, "Well done, Commander. How many Rebels did we kill?" "Well, um, none, milord," the commander meekly replies. "What do you mean?" "The planet was uninhabited." Vader initiates a force choke. "You said there were Rebels here!" The commander struggles to spit out his last words. "I said the inhabitants were all Rebels, not that there were any inhabitants."