C#
Enumerable.All
programming
empty sequence
duplicates

Why does Enumerable.All return true for an empty sequence?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Enumerable.All returning true for an empty sequence surprises many developers the first time they see it. Intuitively, people read "all elements match" and assume there must be at least one element. In formal logic, however, All models universal quantification: "for every element x in set S, predicate P(x) is true." If S is empty, there is no counterexample, so the statement is true. This is called vacuous truth.

This behavior is intentional and useful. Once understood, it helps you write cleaner predicates and avoid unnecessary special-case checks.

Core Sections

1. Observe behavior in code

csharp
1using System;
2using System.Linq;
3
4var empty = Array.Empty<int>();
5var result = empty.All(x => x > 0);
6
7Console.WriteLine(result); // True

No element violates the predicate, so All returns true.

2. Compare All and Any

Any answers existence; All answers universal validity.

csharp
1var values = new[] { 2, 4, 6 };
2
3bool anyOdd = values.Any(x => x % 2 != 0);   // False
4bool allEven = values.All(x => x % 2 == 0);  // True
5
6var empty = Enumerable.Empty<int>();
7bool anyOnEmpty = empty.Any(x => x > 0);     // False
8bool allOnEmpty = empty.All(x => x > 0);     // True

These results are consistent and complementary.

3. Why this design is practical

Many validation flows should pass when there is nothing to validate. For example, "all optional tags are valid" should be true when no tags exist.

csharp
1bool AreTagsValid(IEnumerable<string> tags)
2{
3    return tags.All(t => t.Length <= 20 && !t.Contains(' '));
4}

If tags is empty, returning true avoids extra branching and keeps semantics clean.

4. Require non-empty sequence when business rules demand it

Sometimes your domain needs "all and at least one." Express that explicitly.

csharp
1bool AllPositiveAndNonEmpty(IEnumerable<int> nums)
2{
3    return nums.Any() && nums.All(n => n > 0);
4}

Do not try to force All alone to mean non-empty validation.

5. Performance and enumeration concerns

All short-circuits on first failure. On empty sequences, it returns immediately.

csharp
var ok = source.All(x => ExpensiveCheck(x));

If source is an iterator with side effects, remember Any and All each enumerate. Cache when needed:

csharp
var materialized = source.ToList();
var valid = materialized.Any() && materialized.All(Predicate);

6. Cross-language consistency

This behavior exists in many languages and frameworks (Python all([]) is True, Java Streams allMatch on empty returns true). Understanding this helps when moving between ecosystems.

python
print(all([]))  # True

The principle is mathematical, not C#-specific.

Common Pitfalls

  • Assuming All implies non-empty input and silently accepting missing data.
  • Writing custom loops to override All semantics instead of adding explicit Any() checks.
  • Misreading validation outcomes when optional collections are empty by design.
  • Enumerating expensive iterables multiple times with Any() plus All() without caching.
  • Treating vacuous truth as a framework bug rather than intended universal-quantifier behavior.

Summary

Enumerable.All returns true on empty sequences because it represents universal quantification and no element violates the predicate. This behavior is both mathematically correct and practically useful for optional-data validation. When business logic requires at least one item, combine Any() with All() explicitly. Once you separate existence checks from universal checks, LINQ predicates become clearer and less error-prone.

A practical way to harden this topic in real projects is to add a small operational checklist and treat it as part of your engineering standard, not a one-off fix. Start by creating one minimal failing case and one passing case that represent real input from production logs. Then automate those checks in CI so regressions are caught before release. Add lightweight instrumentation around the critical branch where this logic runs, and include structured fields that let you filter by version, environment, and error type. This gives you fast feedback when behavior changes after dependency upgrades or refactors.

For long-term maintainability on why does enumerableall return true for an empty sequence duplicate, keep one source of truth for helper logic instead of duplicating variants across services or UI layers. Document assumptions near the code, including data format, edge-case behavior, and expected fallback policy. During code review, verify that example inputs and tests cover empty values, malformed values, and high-volume scenarios. Teams that combine explicit assumptions, repeatable tests, and basic observability typically avoid the same category of bug recurring every quarter.


Course illustration
Course illustration

All Rights Reserved.