Collections

Mark
3 min readMar 27, 2021

IEnumerable<T> is a sexy little beast and we use it all over the place. For the retards amongst you, it’s a collection of sorts, but not necessarily one that currently exists or is finite. What it really is, is a hook to an enumerator. This means that you can return IEnumerable<T> all over the shop and not have to commit yourself to using a List<T> or whatever.

Enter stage left deferred execution. You see, I can write something like…

private readonly Random rand = new Random();private IEnumerable<int> GetValues()
{
yield return rand.Next();
yield return rand.Next();
yield return rand.Next();
yield return rand.Next();
}
public void PrintValues()
{
var values = GetValues();
foreach (var value in values) // First loop
Console.WriteLine(value);
foreach (var value in values) // Second loop
Console.WriteLine(value);
}

So say the first loop prints 1, 2, 3, 4 (look, it *could* happen okay?!), then the second loop also prints 1, 2, 3, 4, yeah? Yeah, nah. It generates 4 new random values. The thing here is that where we set ‘values’, we’re not actually setting it to the list of numbers we will eventually print. We’re just pointing it to the GetValues() method. Whenever we execute a foreach loop on it, we’re getting a new Enumerator (i.e. looping over the collection, where the collection is the method… sort of). This is called deferred execution and it happens everywhere you use LINQ. This is why dipshits who can’t code produce performance nightmares by not understanding when to make their results concrete. It’s not entirely their fault though, because — surprise, surprise — Microsoft yet again bollocksed this one up.

You see, the problem is that you don’t know whether an IEnumerable is backed by a concrete collection or not. You end up doing shit like…

public void DoShit(IEnumerable<Foo> foos)
{
foos = foos as ICollection<Foo> ?? foos.ToArray();
...
}

everywhere because you can’t trust what got passed in. It gets worse than this, though. You see, not every concrete generic collection type implements ICollection<T>. Some of them implement IReadOnlyCollection<T>. Some of them implement both. Even which one they implement seems to be pretty random and at the whim of the designers who struggled with the hand-me-downs that is MS’s logic. And I emphasise the ‘downs’ when talking about MS designers.

You see, where Microsoft fucked up here is in calling IReadOnlyCollection<T> IReadOnlyCollection<T> instead of IReadableCollection<T>. Repeat it with me slowly, cunts… Interfaces are supposed to tell you what an implementation *can* do, not what it *can’t* do. What the fuck is a ‘read-only collection’? It’s a collection that can’t be fucking modified. Why the hell do I need to know that it *can’t* be modified? How the fuck are you even thinking of enforcing that? Here’s an idea: if I don’t want my fucking collection to be modified, maybe I won’t implement methods that let it be modified! Holy shit. Fucking rocket surgery here.

Now, imagine if you’d called it IReadableCollection<T> and we had…

public interface IEnumerable<T> { ... }
public interface IReadableCollection<T> : IEnumerable<T> { ... }
public interface ICollection<T> : IReadableCollection<T> { ... }
public interface IReadableList<T> : IReadableCollection<T> { ... }
public interface IList<T> : IReadableList<T>, ICollection<T> { ... }
public class ImmutableArray<T> : IReadableList<T> { ... }
public class List<T> : IList<T> { ... }

… instead of the clusterfuck we currently have whre ImmutableArray<T> implements IList<T> and throws exceptions on half of the methods and List<T> implements IReadOnlyCollection<T> in spite of the fact it’s clearly fucking modifiable (or maybe the pants-on-head retards who made that decision hadn’t heard of fucking ‘cast’).

Of course, that’s not the end of the story, because you can in theory write something with deferred execution that masquerades as an IReadableCollection<T>; but if we could at least agree on what an IReadableCollection<T> is _supposed to be_ we might make some headway.

Oh, and don’t get me started on the bullshit magic that underlies generic arrays. I’ll save that for another day.

--

--