Thread overview
Null-Safe Dereference Operator
Mar 14, 2017
Jolly James
Mar 14, 2017
Jonathan M Davis
Mar 14, 2017
Adam D. Ruppe
March 14, 2017
Does anybody know, if D has a null-safe dereference operator like C# does (?.) or something similar?
March 13, 2017
On Tuesday, March 14, 2017 00:51:02 Jolly James via Digitalmars-d-learn wrote:
> Does anybody know, if D has a null-safe dereference operator like
> C# does (?.) or something similar?

It does not, though if you really wanted to, you could probably create template that did the same thing fairly easily.

- Jonathan M Davis

March 14, 2017
On Tuesday, 14 March 2017 at 01:08:50 UTC, Jonathan M Davis wrote:
> It does not, though if you really wanted to, you could probably create template that did the same thing fairly easily.

I recently added something similar to dom.d, since I wanted to pull a header if present, and was ok with a null string if there wasn't one.

I used to write:

string header;
if(auto e = document.querySelector("h1"))
   header = e.innerText;

but now i can write:

string header = document.optionSelector("h1").innerText;

http://dpldocs.info/experimental-docs/arsd.dom.Element.optionSelector.html


Since the selector syntax is already a DSL for descending into the tree, you don't typically need to chain it far, but the optionSelector magic allows it anyway:

// all of this becomes null-safe dereferencing...
document.optionSelector("h1").firstChild.nextSibling.innerText



The return value is a new type:

http://dpldocs.info/experimental-docs/arsd.dom.MaybeNullElement.html

That uses opDispatch and type checking to wrap. Here is the complete source code, that you might be able to adapt to your object too, or make it REALLY generic and use it anywhere:

---
struct MaybeNullElement(SomeElementType) {

	this(SomeElementType ele) {

		this.element = ele;

	}

	SomeElementType element;


	/// Forwards to the element, wit a null check inserted that propagates null.
	auto opDispatch(string method, T...)(T args) {
		alias type = typeof(__traits(getMember, element, method)(args));
		static if(is(type : Element)) {
			if(element is null)
				return MaybeNullElement!type(null);
			return __traits(getMember, element, method)(args);
		} else static if(is(type == string)) {
			if(element is null)
				return cast(string) null;
			return __traits(getMember, element, method)(args);
		} else static if(is(type == void)) {
			if(element is null)
				return;
			__traits(getMember, element, method)(args);
		} else {
			static assert(0);
		}
	}

	/// Allows implicit casting to the wrapped element.
	alias element this;
}
---




Now, the C# thing is cool because you can use it with any object, but in my experience, I don't *need* it with most objects. I found I mostly want it with XML and JSON, so I just adapted those two specific classes to allow something like the above and now get a decent amount of mileage out of it without needing the general-purpose operator.

You can templatize that MaybeNull thing to work on arbitrary objects too, then write like `NullSafe(obj).chain.as.much.as.you.want` if you like, but another benefit of me finding I mostly wanted it on just those two things is I made a shortcut method: document.optionSelector rather than `nullSafe(document.querySelector)` or whatever.

You could also make some kind of UFCS null safe chainer:

obj.ns.foo.ns.bar

where there is a NullSafe!T ns(T obj) {} that returns a null-safe wrapper; a user-defined function taking the place of the language operator.



So, no, D doesn't have the C# thing, but there are a few other options you can explore to do something similar.