Skip to content

Drop the implicit List<Entity> conversion that makes three params overloads uncallable - #853

Merged
Rafael-SOWNet merged 3 commits into
masterfrom
fix/ambiguous-public-overloads
Aug 10, 2026
Merged

Drop the implicit List<Entity> conversion that makes three params overloads uncallable#853
Rafael-SOWNet merged 3 commits into
masterfrom
fix/ambiguous-public-overloads

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Collaborator

Entity has implicit conversions to itself from both Entity[] and List<Entity>, each building a FiniteSet. The List<Entity> one has a side effect: a list also converts to a single Entity, so for any member that has both an IEnumerable<Entity> overload and a params Entity[] overload, the params form becomes applicable in its expanded form. Neither candidate is better than the other, and the call does not compile.

var equations = new List<Entity> { "x - 1", "y - 2" };

new EquationSystem(equations);   // error CS0121: the call is ambiguous
new FiniteSet(equations);        // error CS0121
MathS.Equations(equations);      // error CS0121

This is not three separate defects. It is one conversion making every params Entity[] overload in the library uncallable with a list — including any added later.

How the three were found

Rather than fix the one I tripped over, I swept all 2602 members in PublicApi.txt for the IEnumerable<T> / T[] single-parameter overload pattern. Exactly three matched, and each was then confirmed by compiling the call in isolation:

call shape before after
new EquationSystem(list) CS0121 OK
new FiniteSet(list) CS0121 OK
MathS.Equations(list) CS0121 OK
the same three with Entity[] OK OK
the same three with IEnumerable<Entity> OK OK
the same three variadic OK OK

Only a concrete List<Entity> ever broke — an array, an IEnumerable<Entity>-typed expression, and the variadic form all compiled fine. That is why it survived to a 2.0 preview.

What changes

The List<Entity> conversion is removed. The Entity[] conversion is kept: an array binds to the params overload in its normal form by an identity conversion, which wins outright, so it never produced the ambiguity.

Entity set = new List<Entity> { 1, 2, 3 };            // no longer compiles
Entity set = new List<Entity> { 1, 2, 3 }.ToSet();    // use this
Entity set = new Entity[] { 1, 2, 3 };                // unchanged

Breaking, so it wants the 2.0 window — recorded in BREAKING-CHANGES.md, and PublicApi.txt updated.

Regression guard

ListArgumentOverloadTest calls all three members with a List<Entity>. The guard is that the test project compiles — restore the conversion and the build breaks, which a runtime assertion could not catch. Sources/.editorconfig gets a per-file header section for the new file, since Tests/UnitTests/Common still carries the 2022 template and IDE0073 is an error.

Verification

  • 6055 C# tests pass, 0 failed, 14 skipped
  • 130 F# wrapper tests pass
  • library, F# wrapper and Utils build clean
  • all ten call shapes in the matrix above compile

The two NETSDK1100 failures in a full solution build are the WinForms/WPF sample projects, which cannot build on Linux; unrelated to this change.

🤖 Generated with Claude Code

Rafael-SOWNet and others added 3 commits August 9, 2026 17:45
…loads uncallable

Entity had implicit conversions to itself from both Entity[] and List<Entity>, each
building a FiniteSet. The List one meant a list also converted to a single Entity,
so for any member with both an IEnumerable<Entity> overload and a params Entity[]
overload the params form became applicable in its expanded form, neither candidate
was better, and the call did not compile:

    var equations = new List<Entity> { "x - 1", "y - 2" };
    new EquationSystem(equations);   // error CS0121
    new FiniteSet(equations);        // error CS0121
    MathS.Equations(equations);      // error CS0121

Not three defects -- one conversion breaking every params Entity[] overload in the
library, including any added later. A sweep of all 2602 members in PublicApi.txt for
the IEnumerable<T>/T[] overload pattern found exactly these three, and each was
confirmed by compiling the call in isolation. The array, IEnumerable<Entity> and
variadic forms always compiled; only a concrete List<Entity> broke, which is how it
reached a 2.0 preview unnoticed.

The Entity[] conversion is kept. An array binds to the params overload in its normal
form by an identity conversion, which wins outright, so it never had the ambiguity.

The new test compiling is the regression guard: restore the conversion and the test
project stops building. Sources/.editorconfig gets a per-file header section for it,
since Tests/UnitTests/Common still carries the 2022 template.

Verified: 6055 C# tests and 130 F# tests pass, the library, F# wrapper and Utils
build clean, and all ten call shapes in the ambiguity matrix now compile.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
preview.1 is published, and it has the conversion. Every other entry in the file
describes a change from 1.3.0 or 1.4.0, so the file's implicit frame is
release-to-release and a reader already on preview.1 would not learn from it that
this one lands on them. Checked: #848 is the only other commit to touch the file
since the preview.1 tag, and what it added is a 1.4.0 section, not a preview delta.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
preview.2 was tagged while this branch sat unmerged, so it ships the conversion too
and the previous commit's "gone from preview.2" is wrong. Naming the version that
removes something from a branch that has not merged bets on merge order; the entry
now says "the release that follows them" and stops guessing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Rafael-SOWNet
Rafael-SOWNet marked this pull request as ready for review August 9, 2026 20:08
@Rafael-SOWNet
Rafael-SOWNet merged commit e55fde6 into master Aug 10, 2026
25 checks passed
@Rafael-SOWNet
Rafael-SOWNet deleted the fix/ambiguous-public-overloads branch August 10, 2026 02:19
Rafael-SOWNet added a commit that referenced this pull request Aug 10, 2026
Closes #861.

#853 removed the conversion from List<Entity> because it made three params overloads
uncallable, and kept the one from Entity[] on the narrow ground that it never produced
that ambiguity -- an array binds to the params overload in its normal form by an identity
conversion, which wins outright.

True, and beside the point, as Happypig375 pointed out on the issue: an array carries an
order and can repeat an element, a set has neither, so the conversion silently discarded
part of what it was handed. That disqualifies it on its own. The question to ask of an
implicit conversion is what it loses, not whether it breaks an overload today, and set
types are built explicitly nearly everywhere for this reason.

Measured before writing anything: removing it broke exactly one place in the repository,
which was the test pinning it. Nothing in the library, no other test, no sample.

That test now says the opposite, and still earns its keep the same way -- the file
compiling is what says the conversion has not come back.

Verified: 6084 C# tests and 130 F# tests pass.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rafael-SOWNet added a commit that referenced this pull request Aug 10, 2026
* Drop the implicit Entity[] to Entity conversion as well

Closes #861.

#853 removed the conversion from List<Entity> because it made three params overloads
uncallable, and kept the one from Entity[] on the narrow ground that it never produced
that ambiguity -- an array binds to the params overload in its normal form by an identity
conversion, which wins outright.

True, and beside the point, as Happypig375 pointed out on the issue: an array carries an
order and can repeat an element, a set has neither, so the conversion silently discarded
part of what it was handed. That disqualifies it on its own. The question to ask of an
implicit conversion is what it loses, not whether it breaks an overload today, and set
types are built explicitly nearly everywhere for this reason.

Measured before writing anything: removing it broke exactly one place in the repository,
which was the test pinning it. Nothing in the library, no other test, no sample.

That test now says the opposite, and still earns its keep the same way -- the file
compiling is what says the conversion has not come back.

Verified: 6084 C# tests and 130 F# tests pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Drop the implicit pair to Interval conversion

Closes #867.

A two-element tuple became an Interval with both endpoints included. A tuple says nothing
about whether either endpoint is in, so the conversion had to supply that, and it chose the
reading opposite to the notation: (1, 5) is the open interval in ordinary mathematical
writing, and this produced the closed one. A caller writing what looks like an open
interval got a closed one, with 1 a member of it, and nothing said so.

Where the array conversion removed in #866 dropped information that was there, this one
produced information that was not. Same fault from the other side, and the same remedy --
ask for the interval by name, which makes the choice visible instead of assumed:

    MathS.Interval(1, 5)                 closed
    MathS.Interval(1, false, 5, false)   open

Measured before writing anything: nothing in the library, the tests, the F# wrapper or the
utilities used it. Zero compile errors on removal, where #866 had one.

The other pairs in the API are left alone, and checked rather than assumed: an integration
Range, the arguments of Substitute, the cases of MathS.Piecewise and ToProvided are all
ordered pairs whose halves have distinct stated roles. None of them has to guess what it
was handed.

Verified: 6085 C# tests and 130 F# tests pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant