Wednesday, July 27, 2011

I want a conditional dot operator

I was writing earlier about features I'd like to have in the .NET Framework and C#, but I forgot a couple. Earlier I wrote about the "slide operator". Now, I'd like to propose the conditional dot or "null dot" operator.

Some people will say this idea makes the language too complex, but I can't seem to get enough language features. I use just about all of C#'s existing features, including the "hidden" ones. And still I can think of many unsupported features that I know would improve productivity, code clarity, or performance... at least for me.

I think it's okay for C# to have tons of features, but the IDE needs to help teach people what they mean. For example, Visual Studio should show the name of an operator in a tooltip when mousing over it, and show a help page for it if the user puts the cursor on it and presses F1.

C# already has a handy "??" operator which lets you choose a default value in case the "first choice" is null:
Console.WriteLine("Your name is {0}.", firstName ?? "(unknown)");
I use this feature somewhat often. But something's missing. I would like, in addition, a "conditional dot" operator, another kind of null guard that deals with cases where an object you want to access might be null. For example, let's say your class has a reference to another class, and you'd like to inform it when something happened:
if (referenceToAnotherClass != null)
referenceToAnotherClass.OnSomethingHappened(info);
Of course you can't call the method if the referenceToAnotherClass is null. It would be nice if we could shorten this to something like
referenceToAnotherClass??.OnSomethingHappened(info);

If the method you want to call returns a value, the "??." operator would substitute null for the return value if the class reference is null. For example,
// firstName might be null; length will be null if firstName is null.
int? length = firstName??.Length;
It would be very natural to combine the "??." operator with the existing "??" operator:
// Equivalent to firstName != null ?  firstName.Length : 0
int length = firstName??.Length ?? 0;
This operator would be most powerful when it is chained together, or used to avoid creating temporary variables:
// If "DatabaseConnection", "PersonTable", and "FirstRow" can all 
// return null, chaining "??." simplifies your code a lot.
var firstName = DatabaseConnection??.Tables.PersonTable??.FirstRow??.Name;

// Equivalent to:
string firstName = null;
var dbc = DatabaseConnection;
if (dbc != null) {
var pt = dbc.Tables.PersonTable;
if (pt != null) {
var fr = pt.FirstRow;
if (fr != null)
firstName = fr.Name;
}
}

The operator should also help invoke events:
public event EventHandler Click;
protected void OnClick()
{
Click??.(this, EventArgs.Empty);
// equivalent to:
if (Click != null)
Click(this, EventArgs.Empty);

// Note: the dot in "??." is still required because "X??(Y)"
// would be indistinguishable from the null coalescing operator.
}
Somebody implemented a "null dot" extension method that provides this kind of "operator" in C#, except that it only supports one out of the four cases I just described, as it requires that the function you want to call return a reference type; it doesn't support void or struct return values. It's also slightly clumsy, and since it relies on a lambda, it hurts performance. To work well, this feature needs language support.

Right now I am working with code that often converts objects to strings (the objects are usually strings, but may be something else). The object is sometimes null, so I write
string s = (obj ?? "").ToString();
This works fine, but it's less efficient than it could be, because if obj == null, a virtual call to ToString() will be called on the empty string "". If the "null dot" or "conditional dot" operator existed, I would write this code as
string s = obj??.ToString() ?? "";
or even
string s = obj??.ToString();
if a null result is acceptable.

I know that an operator like this exists in some other languages, but I don't which ones at the moment. Anybody remember?

P.S. Microsoft somehow forgot to include a compound assignment operator, which should work like the other compound assignment operators.

twosies += 2; // equivalent to twosies = twosies + 2
doubled *= 2; // equivalent to doubled = doubled * 2
// ensure myList is not null
myList ??= new List<int>(); // myList = myList ?? new List<int>()

1 comment:

Oliver Hanappi said...

In Objective-C sending a message (something like invoking a method) to nil results in nil (or 0 etc.) and will not throw a runtime error. See http://stackoverflow.com/questions/156395/sending-a-message-to-nil for details.

I would also like to have this behaviour in C#. I am often confronted with the fact to export data to some files and I usually need to write code like "person.PhoneNumbers.FirstOrDefault().PhoneCenter.Address.Name.Abbreviation...." Normally, I end up with a helper Get.Value(() => x.y) which returns the value of the lamda, but surrounds the whole invocation chain with a try catch in order to catch a NullPointerException.