www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Null-Safe Dereference Operator

reply Jolly James <j.j jmail.com> writes:
Does anybody know, if D has a null-safe dereference operator like 

Mar 13 2017
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
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

It does not, though if you really wanted to, you could probably create template that did the same thing fairly easily. - Jonathan M Davis
Mar 13 2017
parent Adam D. Ruppe <destructionator gmail.com> writes:
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; } --- 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. options you can explore to do something similar.
Mar 13 2017