Most languages have a version of the switch statement as far as I’m aware; I must admit, I don’t remember one from Spectrum Basic, but ever since then, I don’t think I’ve come across a language that doesn’t have one. The switch statement in C was interesting. For example, the following was totally valid:
switch (value) { case 1: printf("hello "); case 2: printf("world"); }
If you gave it a value of 1 would print “hello world”. When C# came out, they insisted on using breaks at the end of case statements, or having no code (admittedly there were a few bugs in C caused by accidentally leaving break statements out):
int value = 1; switch (value) { case 1: Console.Write("hello "); break; case 2: Console.Write("world"); break; }
Anyway, fast forward around 17 years to C# 7.x, and it basically has the same switch statement; in fact, as far as I’m aware, you could write this switch statement in C# 1.1 and it would compile fine. There’s nothing wrong with it, so I imagine MS were thinking why fix it if it’s not broken.
There are limitations, however; for example, what if I want to return the string, like this:
int value = 1; string greeting = string.Empty; switch (value) { case 1: greeting = "hello "; break; case 2: greeting = "world"; break; } Console.WriteLine(greeting);
Now it looks a bit cumbersome. What if we could write it like this:
int value = 1; string greeting = value switch { 1 => "hello ", 2 => "world", _ => string.Empty }; Console.WriteLine(greeting);
From C# 8, you can do just that. The switch statement will return its value. The case syntax is disposed of, and there’s no need for a break statement (which, to be fair, can encourage people to write large swathes of code inside the switch statement – if you don’t believe me then have a look in the Asp.Net Core source!).
And that’s not all. Pattern matching has also been brought in; for example, take the following simple class structure:
interface IAnimal { void Eat(); void Sleep(); string Name { get;} } class Dog : IAnimal { public string Name { get => "Fido"; } public void Eat() { Console.WriteLine("Dog Eats"); } public void Sleep() { Console.WriteLine("Dog Sleeps"); } } class Cat : IAnimal { public string Name { get => "Lemmy"; } public void Eat() { Console.WriteLine("Cat Eats"); } public void Sleep() { Console.WriteLine("Cat Sleeps"); } }
We can put that into a switch statement like this:
IAnimal animal = new Cat(); string greeting = animal switch { Dog d => $"hello dog {d.Name}", Cat c => $"hello cat {c.Name}", _ => string.Empty }; Console.WriteLine(greeting);
We can actually do better that this (obviously better is a relative term). Let’s say that we wanted to do something specific for our particular cat:
IAnimal animal = new Cat(); string greeting = animal switch { Dog d => $"hello dog {d.Name}", Cat c when c.Name == "Lemmy" => $"Hello motorcat!", Cat c => $"hello cat {c.Name}", _ => string.Empty }; Console.WriteLine(greeting);
It’s a bit of a silly and contrived example, but it does illustrate the point; further, if you switch the case statements around for the general and specific form of Cat, you’ll get a compile error!