JBlam.Collections.ValueArray
0.0.2
dotnet add package JBlam.Collections.ValueArray --version 0.0.2
NuGet\Install-Package JBlam.Collections.ValueArray -Version 0.0.2
<PackageReference Include="JBlam.Collections.ValueArray" Version="0.0.2" />
paket add JBlam.Collections.ValueArray --version 0.0.2
#r "nuget: JBlam.Collections.ValueArray, 0.0.2"
// Install JBlam.Collections.ValueArray as a Cake Addin #addin nuget:?package=JBlam.Collections.ValueArray&version=0.0.2 // Install JBlam.Collections.ValueArray as a Cake Tool #tool nuget:?package=JBlam.Collections.ValueArray&version=0.0.2
JBlam.Collections.ValueArray
An immutable array wrapper with value equality semantics.
Usage
using JBlam.Collections.ValueArray;
// Initialise with a collection expression.
ValueArray<int> arr = [1, 2, 3];
// Iterate like any other IEnumerable.
foreach (var value in arr)
Console.WriteLine(value);
// Collect IEnumerables into a ValueArray instance.
var second = Enumerable.Range(1, 3).ToValueArray();
// Value equality!
Console.WriteLine($"ValueArrays are equal? {arr == second}");
// Default value does not throw!
var empty = default(ValueArray<int>);
Console.WriteLine($"Am I safe from NullReferenceExceptions in value types now? {empty.Length == 0}");
// Implicit conversion to/from ImmutableArray<T> means you can use ImmutableArray.Builder.
var builder = System.Collections.Immutable.ImmutableArray.CreateBuilder<int>();
builder.Add(1);
builder.Add(2);
builder.Add(3);
System.Collections.Immutable.ImmutableArray<int> immutableArray = builder.ToImmutable();
// implicit conversion happens here ↓
ValueArray<int> third = immutableArray;
Console.WriteLine($"Converted from ImmutableArray? {arr == third}");
Why not ImmutableArray?
This is a drop in replacement for System.Collections.Immutable.ImmutableArray<T>
which aims to resolve three issues:
- The
default
value is logically empty, rather than exploding with null reference exceptions. - It implements value equality, and is therefore suitable to use in record types.
- It overrides the default string representation to print at least some of the contents, similar to the generated
ToString
for record types.
Platform Support
ValueArray
targets net8.0
which at time of writing was the LTS release. I've also multitargeted netstandard2.0
because I want to use it in Roslyn analysers and source-generators; and also net6.0
because I have some work projects which use that.
The System.Text.Json
integration is not available for netstandard2.0
because it's outside my use-case. Minor bits of API are also excluded, but mostly I'm providing some shims.
Implementation details
The struct layout of ValueArray
is identical to ImmutableArray
. The type design is similar, except it special-cases the default value, provides value equality, and overrides ToString to print its contents.
Converting to and from ImmutableArray<T>
is effectively free. (Roughly the cost of copying a single reference.)
I will release this with minimal API around it, on the understanding that if you want "immutable mutations" you can easily convert to the equivalent ImmutableArray, do your business, and convert back.
Rants
ImmutableArray<T>
is a value type which wraps a hidden reference to a reference type, and as such default
contains a null reference. This is a massive footgun, because the only safe way to interact with an ImmutableArray
is to inspect it for IsDefault
; that's incredibly unexpected because C# programmers don't normally inspect value types for null. It also hides the null reference from the nullable type annotation system, which otherwise makes NullReferenceException
more-or-less a solved problem.
ValueArray<T>
solves this issue by making default
logically equal to an empty array.
But wait! if default
is equal to []
, doesn't that mean equality is broken? Well, have I got a story to tell you ...
ImmutableArray<T>
is a value type which wraps a hidden reference to a reference type and doesn't manage equality meaning that ImmutableArray<T>.Equals
is effectively reference-equality on the hidden reference. This is again highly surprising for the C# developer who assumes that value types support value equality, because they are values.
ValueArray<T>
solves this issue by making Equals
return sequence equality. Yes, that's O(n). I suggest not making ValueArray<T>
wrap multiple gigabytes of data.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Collections.Immutable (>= 8.0.0)
-
net6.0
- System.Collections.Immutable (>= 8.0.0)
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
0.0.2 | 108 | 5/20/2024 |
0.0.2; Initial release as an independent package