DEV Community

Simon Reynolds
Simon Reynolds

Posted on • Originally published at simonreynolds.ie on

The continued theft of ideas by C#

The continued theft of ideas by C#

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

var squaredValues = intCollection.Select(x => x * x).ToList();
Enter fullscreen mode Exit fullscreen mode

is clearer and simpler than this?

List<int> squaredValues = new List<int>();
foreach (int i in intCollection)
{
    int squared = i * i;
    squaredValues.Add(squared);
}
Enter fullscreen mode Exit fullscreen mode

But now, now it gets even worse! C# 8.0 has polluted the language with such unnecessary things as nullable reference types. 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.

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>();
}
Enter fullscreen mode Exit fullscreen mode

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!

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"
    };
Enter fullscreen mode Exit fullscreen mode

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 company using F# in production?

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.

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";
Enter fullscreen mode Exit fullscreen mode

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?

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);
Enter fullscreen mode Exit fullscreen mode

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?

var simon = new Person("Simon", "Reynolds");
var evan = simon with { FirstName = "Evan" };

var (firstName, lastName) = evan; // ("Evan", "Taite")
Enter fullscreen mode Exit fullscreen mode

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? 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 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?

Latest comments (2)

Collapse
 
sam_ferree profile image
Sam Ferree

I wish they’d steal discriminated unions...

We have the switch expression, just let me constrain a type to a finite list so it can be exhaustive

Collapse
 
saint4eva profile image
saint4eva

enum class. It is coming πŸ˜‚