The affair of the C# bang bang - !! - operator
/A programming language is like any other language. It must evolve over time to reflect the ways that it is used. One of the things I love about C# is how it has grown over the years. One of the latest changes is the addition of a !! operator (otherwise known as the “bang bang” operator). This is causing a bit of debate, which is great because changes to a programming language should always be made on the basis of a proper discussion. But you might be wondering what all the debate is about. So here’s a quick explanation of what is going on.
C# has always had methods. A method is a thing you can ask an object to do. For example, you might have an object which you can ask to serve a drink:
barkeeper.serveBeer();
barkeeper.serveCoffee();
Then you might decide that rather than have a lot of different methods for different kinds of drink it would be easier to make a method that accepts an argument that tells it the kind of drink that is required:
barkeeper.serveDrink("Beer");
barkeeper.serveDrink("Coffee");
The serveDrink method can look at the value of the argument and decide what to do:
void serveDrink(string drinkName)
{
// test the name and make an appropriate drink
}
So far so sensible, although we have made things slightly easier in one respect (we can use serveDrink method to serve any drink rather than having to make lots of methods) by making things slightly more difficult in another (the serveDrink method has to decide what drink is to be made and what to do if a matching name is not found). For example, what should happen when the following code runs?:
barkeeper.serveDrink("BEER");
The above code is asking for a beer, but the name is all capital letters. Does the method deliver a "Beer", or does it fail with an error. If it fails with an error, how does the user of the program know that an error has occurred? At this point we have to invent a convention for our application. We might say that the serveDrink method will throw an exception if it is given a drink type it doesn't recognise. That's fine as long as the behaviour is documented so that users of the method now how to use it.
But what about bang bang? I hear you ask. The operator is intended to make life easier for programmers by automating the handing of null references. Consider what would happen if someone did this:
barkeeper.serveDrink(null);
This code will ask for a drink but provide a null reference as the drink description. A null reference is not the same as an empty string, it is a reference that points to nothing. This is like asking the barkeeper for a drink and then falling over on the floor before you tell them what you want. An attempt by the serveDrink method to use this null reference will result in the method failing in some way.
Naughty hackers love this kind of situation. They might discover that asking for a null drink causes the serveDrink function to crash just after it has opened a bar tab, so that they can then continue to order drinks for free. They might find it serves out the most expensive drink in the bar.
As the person who is writing the serveDrink method you don't want anything like this to happen. So in the method you add a test to make sure that the argument is not a null value:
void serveDrink(string drinkName)
{
if (drinkName is null) {
throw new ArgumentNullException(nameof(drinkName));
}
// test the name and make an appropriate drink
}
The first thing this serveDrink method does is check to see if the drinkName is null. If it is null an exception is thrown which exits the method instantly. This exception may or may not be handled by the caller, that is up to them. However, we have made sure that the serveDrink method won't do anything stupid if given a null reference. (of course we now have to worry about the issues that might be caused by this method throwing an exception thougth - welcome to the world of error handling).
What the bang bang operator does is make the above test for us automatically.
void serveDrink(string drinkName!!)
{
// test the name and make an appropriate drink
}
In this verson of the code an exception is thrown if drinkName is null. I don't have to remember to add the call. This might make my programs slightly safer. But it also means that readers of the code need to understand what !! means in this context. They might look at it and think that the drink is very important, or hot, or something else. They might not know what it does and add their own tests for null which don't do what they expect. Hence the debate.
My opinion? I split language features into two categories. Cake and icing. This is definitely icing. I'd never use it personally, as I like my error handling code to be very visible to someone reading my programs. Plus I don't like situations where readers need to know "special stuff" to make sense of what they see. However, it's not a thing I'd stress about too much either way. I just love the way that C# is still striving to move forwards.
You can find out more about this proposal and the debate here.