Null-Safe Dereference Operator
Adam D. Ruppe via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Mon Mar 13 21:00:03 PDT 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.
More information about the Digitalmars-d-learn
mailing list