The continued theft of ideas by C#
Tags: csharp, fsharp, dotnet
Published: 2020-06-20 15:00:24

---
title: The continued theft of ideas by C#
published: true
date: 2020-06-19 08:00:00 UTC
tags: csharp,fsharp,dotnet
canonical_url: https://SimonReynolds.ie/the-continued-theft-of-good-ideas-by-csharp/
---

 ![The continued theft of ideas by C#](https://images.unsplash.com/photo-1487795924438-a3cb4b7a5556?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=2000&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ)

Back in the good old days, C# was .NET was Windows. Sure there were antique languages like VB.NET and ivory tower academia from F# but [_real_ developers](https://xkcd.com/378/) used C# and the language was just fine as it was.

Sure, some additions helped, generics were ok even if they did smell suspiciously like Java. But honestly, a lot of the newer "features" of C# are just syntactic sugar that don't really help anything.

I mean, who really needs things like type inference or ternary operators? And that LINQ syntax?! Who can honestly claim that this

<!--kg-card-begin: markdown-->
```csharp
var squaredValues = intCollection.Select(x => x * x).ToList();
```
<!--kg-card-end: markdown-->

is clearer and simpler than this?

<!--kg-card-begin: markdown-->
```csharp
List<int> squaredValues = new List<int>();
foreach (int i in intCollection)
{
    int squared = i * i;
    squaredValues.Add(squared);
}
```
<!--kg-card-end: markdown-->

But now, now it gets even worse! C# 8.0 has polluted the language with such unnecessary things as [nullable reference types](https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references). Maybe I like spending hours hunting through code to track down why something is null when it shouldn't be.

As if that wasn't bad enough, now we have new operators too! We have a fancy new "null-coalescing" operator where a simple if statement would suffice.

<!--kg-card-begin: markdown-->
```csharp
List<int> mayBeNull = null;

// Who on earth would do this?
List<int> mustNotBeNull = mayBeNull ??= new List<int>();

// When they can do this?
// What does it matter if someone forgets to do the if check
// when it's their tenth time writing code like this today?
List<int> mustNotBeNull = mayBeNull;
if (mustNotBeNull == null)
{
    mustNotBeNull = new List<int>();
}
```
<!--kg-card-end: markdown-->

But worst of all now they've taken ideas from dangerously fringe languages like F#, with such strange concepts as Pattern Matching, even going so far as to be able to use them on tuples!

<!--kg-card-begin: markdown-->
```csharp
public enum Hand { Rock, Paper, Scissors }

public static string RockPaperScissors(Hand first, Hand second)
    => (first, second) switch
    {
        (Hand.Rock, Hand.Paper) => "rock is covered by paper. Paper wins.",
        (Hand.Rock, Hand.Scissors) => "rock breaks scissors. Rock wins.",
        (Hand.Paper, Hand.Rock) => "paper covers rock. Paper wins.",
        (Hand.Paper, Hand.Scissors) => "paper is cut by scissors. Scissors wins.",
        (Hand.Scissors, Hand.Rock) => "scissors is broken by rock. Rock wins.",
        (Hand.Scissors, Hand.Paper) => "scissors cuts paper. Scissors wins.",
        (_, _) => "tie"
    };
```
<!--kg-card-end: markdown-->

If something like Rock, Paper, Scissors can be expressed in a single method that will even give a compiler warning if every possible combination isn't covered in the switch statement, then how on earth is a developer supposed to be able to justify a large design or testing budget?!

But it gets even worse, the upcoming C# 9.0 is adding more features inspired by F#! Honestly, who has even heard of a [successful](https://www.letsgetchecked.com/) [company](https://www.walmart.com/) [using F#](https://www.olo.com/) [in production](https://www.carsales.com.au/)?

But no, it had to take inspiration from this "language" (it doesn't even use semicolons). Adding such unnecessary new things as an `init` accessor that allows you to specify that a property can only be written to at object initialisation.

<!--kg-card-begin: markdown-->
```csharp
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

var simon = new Person
{
   FirstName = "Simon",
   LastName = "Reynolds"
};

// Why does it matter that this code is legal?
// Surely we'd all just remember to not make this mistake?
simon.FirstName = "Evan";

public class Person2
{
    public string FirstName { get; init; }
    public string LastName { get; init; }
}

var simon = new Person2
{
   FirstName = "Simon",
   LastName = "Reynolds"
};

// Is having to learn a new accessor really worth avoiding mistakes like this?
// Who cares that this would be a compiler error instead of a bug report?
simon.FirstName = "Arlo";
```
<!--kg-card-end: markdown-->

What does it matter if a property is mutable and can be changed at any point? If it's not meant to be written to after creation then that's on us as developers to be professional enough to remember not to write to it!

But still that's not enough, C# 9.0 goes further and introduces the idea of a class being an automatically immutable "record" class. Why on earth would anyone want an object that just represents data and is guaranteed not to be accidentally modified? Why would we need an object that is considered equal to another simply because all the properties of it have the same values?

<!--kg-card-begin: markdown-->
```csharp
public data class Person // What is this "data" keyword?!
{
    public string FirstName { get; init; }
    public string LastName { get; init; }
}

// This is the same but what are we really gaining from this brevity?
public data class Person { string FirstName; string LastName; }

// Or even more extreme brevity?
public data class Person(string FirstName; string LastName);
```
<!--kg-card-end: markdown-->

Does it really help to compress 5 lines down to one? How does that make things simpler?

What if we want to change a record? So instead of modifying it we just have to create a new one even though most fields will have the same values? How can that be done without having to copy each field manually?

<!--kg-card-begin: markdown-->
```csharp
var simon = new Person("Simon", "Reynolds");
var evan = simon with { FirstName = "Evan" };

var (firstName, lastName) = evan; // ("Evan", "Taite")
```
<!--kg-card-end: markdown-->

Oh.....ok, I guess that's pretty convenient. And granted, we got automatic deconstruction back into separate fields for free as well but still....this can't be that useful in real life scenarios, right?

It's not as if there's an entire application architecture based on recording the entire history of an object at every point in its history instead of just updating a single instance of it, [right](https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing)? Why would we ever need to audit our records and tell you _why, how or when_ a change occurred?

C# needs to drop all [these new plans](https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/) and return to its roots as a plain object-oriented language where anything can be null, state can be changed by anything and where dozens of if/else statements are used instead of single switches that cover all cases. If we carry on down this dangerous path how are we supposed to show our skills? Which will look more impressive, fixing a critical bug at 3AM on a Sunday morning or leaving work on time each day because we've been able to prevent the bug in the first place?