Skip to content

Commit 67e4bc2

Browse files
Rafael-SOWNetclaude
andcommitted
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>
1 parent 0f73690 commit 67e4bc2

5 files changed

Lines changed: 121 additions & 2 deletions

File tree

‎BREAKING-CHANGES.md‎

Lines changed: 46 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,51 @@ 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+
**What breaks.** Assigning a list where an `Entity` is expected:
131+
132+
```csharp
133+
Entity set = new List<Entity> { 1, 2, 3 }; // no longer compiles
134+
```
135+
136+
Write one of these instead:
137+
138+
```csharp
139+
Entity set = new FiniteSet(new List<Entity> { 1, 2, 3 });
140+
Entity set = new List<Entity> { 1, 2, 3 }.ToSet();
141+
Entity set = new Entity[] { 1, 2, 3 }; // the array conversion is unchanged
142+
```
143+
144+
The `Entity[]` conversion is kept: an array argument binds to the `params` overload in its normal
145+
form by an identity conversion, which beats the alternatives outright, so it never produced the
146+
ambiguity.
147+
102148
### `Minusf`'s two operands exchanged names
103149

104150
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)