Skip to content

Commit e55fde6

Browse files
Drop the implicit List<Entity> conversion that makes three params overloads uncallable (#853)
* Drop the implicit List<Entity> conversion that made three params overloads 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> * Say that this break falls between preview.1 and preview.2 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> * Correct which previews carry the conversion 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> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 181a42a commit e55fde6

5 files changed

Lines changed: 126 additions & 2 deletions

File tree

‎BREAKING-CHANGES.md‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ read first.
5757
| loud | `MathS.Quantum.IsNormalised` | the British spelling | `MathS.Quantum.IsNormalized` |
5858
| loud | the target frameworks | `net7.0;netstandard2.0` | `netstandard2.0;net8.0;net10.0` |
5959
| **silent** | `abs(x) = c` for a negative `c` | a set of non-solutions | the empty set |
60+
| loud | implicit `List<Entity>` to `Entity` | made a `FiniteSet`, and made three `params` overloads uncallable | removed |
6061

6162
---
6263

@@ -99,6 +100,56 @@ the built assemblies: present in `net8.0` and `net10.0`, absent from `netstandar
99100

100101
## Types and members
101102

103+
### The implicit conversion from `List<Entity>` is removed
104+
105+
`Entity` had two implicit conversions from a collection, both building a `FiniteSet`:
106+
107+
```csharp
108+
public static implicit operator Entity(Entity[] elements);
109+
public static implicit operator Entity(List<Entity> elements); // removed
110+
```
111+
112+
The second one made three public members impossible to call with a `List<Entity>`:
113+
114+
```csharp
115+
var equations = new List<Entity> { "x - 1", "y - 2" };
116+
new EquationSystem(equations); // error CS0121: the call is ambiguous
117+
new FiniteSet(equations); // error CS0121
118+
MathS.Equations(equations); // error CS0121
119+
```
120+
121+
Each of those has both an `IEnumerable<Entity>` overload and a `params Entity[]` overload. With
122+
the conversion in place a `List<Entity>` also converts to a single `Entity`, so the `params`
123+
overload becomes applicable in its expanded form, neither candidate is better than the other,
124+
and the call does not compile. The array, `IEnumerable<Entity>`, and variadic forms were always
125+
fine — only a concrete `List<Entity>` broke, which is why it survived to a 2.0 preview.
126+
127+
This was not three separate defects. One conversion made *every* `params Entity[]` overload in
128+
the library uncallable with a list, including any added later.
129+
130+
**This one moves between previews.** The conversion is in `2.0.0-preview.1` and
131+
`2.0.0-preview.2`, both published, and is removed in the release that follows them. It is so
132+
far the only entry here that changes between two previews rather than between releases: a
133+
reader coming from 1.3.0 or 1.4.0 can ignore the distinction, one already on a preview cannot.
134+
135+
**What breaks.** Assigning a list where an `Entity` is expected:
136+
137+
```csharp
138+
Entity set = new List<Entity> { 1, 2, 3 }; // no longer compiles
139+
```
140+
141+
Write one of these instead:
142+
143+
```csharp
144+
Entity set = new FiniteSet(new List<Entity> { 1, 2, 3 });
145+
Entity set = new List<Entity> { 1, 2, 3 }.ToSet();
146+
Entity set = new Entity[] { 1, 2, 3 }; // the array conversion is unchanged
147+
```
148+
149+
The `Entity[]` conversion is kept: an array argument binds to the `params` overload in its normal
150+
form by an identity conversion, which beats the alternatives outright, so it never produced the
151+
ambiguity.
152+
102153
### `Minusf`'s two operands exchanged names
103154

104155
In `a - b`, `a` is the minuend and `b` is the subtrahend. The record declared them the other way

‎Sources/.editorconfig‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed
2424
[Tests/UnitTests/Core/Transformations/*.cs]
2525
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n
2626

27+
[Tests/UnitTests/Common/ListArgumentOverloadTest.cs]
28+
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n
29+
2730
# A new file in a directory whose other files predate it, so the section is on the file
2831
# rather than the folder.
2932
[AngouriMath/Core/Entity/Continuous/Entity.Continuous.{Floors,Rounding}.Classes.cs]

‎Sources/AngouriMath/Core/Entity/Omni/Entity.Set.cs‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ public bool Contains(Entity entity)
8383
public static implicit operator Entity(Domain domain) => Set.SpecialSet.Create(domain);
8484
public static implicit operator Entity((Entity left, Entity right) interval) => new Interval(interval.left, true, interval.right, true);
8585
public static implicit operator Entity(Entity[] elements) => new FiniteSet(elements);
86-
public static implicit operator Entity(List<Entity> elements) => new FiniteSet((IEnumerable<Entity>)elements);
8786
#pragma warning restore CS1591
8887

8988
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//
2+
// Copyright (c) 2019-2026 Angouri.
3+
// AngouriMath is licensed under MIT.
4+
// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
5+
// Website: https://am.angouri.org.
6+
//
7+
8+
using System.Collections.Generic;
9+
using AngouriMath;
10+
using AngouriMath.Core;
11+
using Xunit;
12+
13+
namespace AngouriMath.Tests.Common
14+
{
15+
/// <summary>
16+
/// Every member here takes both an <see cref="IEnumerable{T}"/> and a <c>params Entity[]</c>.
17+
/// While <c>Entity</c> also had an implicit conversion from <c>List&lt;Entity&gt;</c>, a list
18+
/// argument matched the params overload in its expanded form as well, neither candidate was
19+
/// better than the other, and none of these calls compiled -- CS0121. The conversion is gone;
20+
/// this file failing to compile is what says it has not come back.
21+
/// </summary>
22+
[Trait("Area", "Common")]
23+
public sealed class ListArgumentOverloadTest
24+
{
25+
static List<Entity> Equations => new() { "x - 1", "y - 2" };
26+
27+
[Fact]
28+
public void EquationSystemTakesAList()
29+
{
30+
var solutions = new EquationSystem(Equations).Solve("x", "y");
31+
Assert.NotNull(solutions);
32+
Assert.Equal(1, solutions.RowCount);
33+
Assert.Equal(2, solutions.ColumnCount);
34+
}
35+
36+
[Fact]
37+
public void MathSEquationsTakesAList()
38+
{
39+
var solutions = MathS.Equations(Equations).Solve("x", "y");
40+
Assert.NotNull(solutions);
41+
Assert.Equal(1, solutions.RowCount);
42+
}
43+
44+
[Fact]
45+
public void FiniteSetTakesAList()
46+
{
47+
var set = new Entity.Set.FiniteSet(new List<Entity> { 1, 2, 3 });
48+
Assert.Equal(3, set.Count);
49+
}
50+
51+
/// <summary>The array and variadic forms were never ambiguous, and must stay that way.</summary>
52+
[Fact]
53+
public void ArrayAndVariadicFormsStillBind()
54+
{
55+
Entity[] equations = { "x - 1", "y - 2" };
56+
Assert.NotNull(new EquationSystem(equations).Solve("x", "y"));
57+
Assert.NotNull(new EquationSystem("x - 1", "y - 2").Solve("x", "y"));
58+
Assert.Equal(3, new Entity.Set.FiniteSet(1, 2, 3).Count);
59+
}
60+
61+
/// <summary>
62+
/// The conversion from an array is deliberately kept, so an array in an
63+
/// <c>Entity</c> position is still a set.
64+
/// </summary>
65+
[Fact]
66+
public void ArrayStillConvertsToASet()
67+
{
68+
Entity set = new Entity[] { 1, 2, 3 };
69+
Assert.Equal(new Entity.Set.FiniteSet(1, 2, 3), set);
70+
}
71+
}
72+
}

‎Sources/Tests/UnitTests/Common/PublicApi.txt‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2132,7 +2132,6 @@ AngouriMath.Entity.op_Implicit(PeterO.Numbers.EInteger) : AngouriMath.Entity
21322132
AngouriMath.Entity.op_Implicit(PeterO.Numbers.ERational) : AngouriMath.Entity
21332133
AngouriMath.Entity.op_Implicit(System.Boolean) : AngouriMath.Entity
21342134
AngouriMath.Entity.op_Implicit(System.Byte) : AngouriMath.Entity
2135-
AngouriMath.Entity.op_Implicit(System.Collections.Generic.List<AngouriMath.Entity>) : AngouriMath.Entity
21362135
AngouriMath.Entity.op_Implicit(System.Decimal) : AngouriMath.Entity
21372136
AngouriMath.Entity.op_Implicit(System.Double) : AngouriMath.Entity
21382137
AngouriMath.Entity.op_Implicit(System.Int16) : AngouriMath.Entity

0 commit comments

Comments
 (0)