Is there a safe navigation operator for C++?
The best you can do is collapse all the member accesses into one function. This assumes without checking that everything is a pointer:
template <class C, class PM, class... PMs>
auto access(C* c, PM pm, PMs... pms) {
if constexpr(sizeof...(pms) == 0) {
return c ? std::invoke(pm, c) : nullptr;
} else {
return c ? access(std::invoke(pm, c), pms...) : nullptr;
}
}
Which lets you write:
if (auto r = access(p, &P::q, &Q::r); r) {
r->doSomething();
}
That's ok. Alternatively, you could go a little wild with operator overloading and produce something like:
template <class T>
struct wrap {
wrap(T* t) : t(t) { }
T* t;
template <class PM>
auto operator->*(PM pm) {
return ::wrap{t ? std::invoke(pm, t) : nullptr};
}
explicit operator bool() const { return t; }
T* operator->() { return t; }
};
which lets you write:
if (auto r = wrap{p}->*&P::q->*&Q::r; r) {
r->doSomething();
}
That's also ok. There's unfortunately no ->?
or .?
like operator, so we kind of have to work around the edges.
Safe Navigation Operator in C#?
For such cases I tend to use an extension method called IfNotNull
:
public static OUT IfNotNull<IN, OUT>(this IN v, Func<IN, OUT> f)
where IN : class where OUT : class
{
return v == null ? null : f(v);
}
More sophisticated is to introduce the notion of a Maybe . An example was brought by derick bailey here.
Update:
As of C# 6 there is now a null-propagating operator which syntax-wise looks exactly like the Groovy one.
Safe Navigation Operator with Any()
Here is what C# reference says about ?.
operator:
x?.y – null conditional member access. Returns null if the left hand
operand is null.
Since at compile time the compiler doesn't knows whether the expression will evaluate to a non-null value, the compiler infers the type as Nullable<bool>
Since you are chaining the ?.
operator this line from msdn documentation is relevant too:
The null-condition operators are
short-circuiting. If one operation in a chain of conditional member
access and index operation returns null, then the rest of the chain’s
execution stops. Other operations with lower precedence in the
expression continue. For example, E in the following always executes,
and the ?? and == operations execute.
Can a C# Safe Navigation Operator (?.) be used to check if Object is null, as well as property?
The first is equivalent to
if (_instanceData != null && _instanceData.DataSourceType != null && Util.IsEntityBacked(_instanceData.DataSourceType) {// code}
The second is equivalent to
if (LockAcquired && _instanceData != null && _instanceData.ObjInfo != null) {// code}
So it will check if _instanceData is null, then check if _instanceData.DataSourceType is null, then the last condition. As you said, this is just syntactical sugar so you don't have to write two != null
conditions. The IL code that results is exactly the same, so its a matter of preference whether or not to use the operator.
It does save a TON of space when accessing deeply nested properties, which is where its most useful
if(Parent != null)
{
if(Parent.Child != null)
{
if(Parent.Child.GrandChild != null)
{
Parent.Child.GrandChild.GreatGrandChild.name = "Parent IV";
}
}
}
becomes
Parent?.Child?.GrandChild?.GreatGrandChild.name = "Parent IV";
Saves a lot of space! Even if you collapsed all the ifs into one statement it still saves loads of keystrokes and screen noise.
C# Safe navigation operator - what is actually going on?
Let's walk through this logically.
var f = ???;
var i = f?.Measure;
var t = i.HasValue;
We don't know if f
is null or not.
- If
f
is null, then the result (i
) isnull
- If
f
is not null, then the result (i
) is anint
Therefore, i
is defined as int?
, and t
is a bool
Now, let's walk through this:
var f = ???;
var i = f?.Measure.HasValue;
- If
f
is null, then the result (i
) is null - If
f
is not null, then the result (i
) isMeasure.HasValue
, which is a bool.
Therefore, i
is a bool?
.
If f
is null, we short-circuit and return null. If it's not, we return the bool
result of .HasValue
.
Essentially, when using ?.
- the return type must be a reference value, or a Nullable<T>
, as the expression can short circuit to return null.
What's the best implementation of safe navigation operator
That operator does not exist in C#. You could do it with an inline-if
int respId = SessionData.CurrentSeminar != null ?
SessionData.CurrentSeminar.SeminCbaRespId : default(int);
or as an extension method.
var respId = SessionData.CurrentSeminar.GetSeminCbaRespId();
public static int GetSeminCbaRespId(this typeofCurrentSeminar CurrentSeminar)
{
return CurrentSeminar != null ? CurrentSeminar.SeminCbaRespId : default(int);
}
Safe Navigation of indexed objects
Based on the Language Feature Status Page it looks like you want:
var singleElement2 = myClass2?.ArrayOfStrings?[0];
The example on the page is:
customer?.Orders?[5]?.$price
... admittedly the $price
part has been withdrawn now, I believe, but I would expect the indexed null propagation to work.
Safe navigation operator (?.) or (!.) and null property paths
Since TypeScript 3.7 was released you can use optional chaining now.
Property example:
let x = foo?.bar.baz();
This is equvalent to:
let x = (foo === null || foo === undefined)
? undefined
: foo.bar.baz();
Moreover you can call:
Optional Call
function(otherFn: (par: string) => void) {
otherFn?.("some value");
}
otherFn
will be called only if otherFn
won't be equal to null
or undefined
Usage optional chaining in IF statement
This:
if (someObj && someObj.someProperty) {
// ...
}
can be replaced now with this
if (someObj?.someProperty) {
// ...
}
Ref: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html
What does the safe navigation operator look like for closures in Groovy?
You should be able to use the longer call()
form, ie:
c?.call( 'hello world?' )
Related Topics
C++: Timing in Linux (Using Clock()) Is Out of Sync (Due to Openmp)
How to Check Deallocation of Memory
Equality-Compare Std::Weak_Ptr
How to Overload the Conditional Operator
Branch Prediction on a Function Pointer
How to Know the Right Max Size of Vector? Max_Size()? But No
Why to Use Higher Base for Implementing Bigint
Why Do Sin(45) and Cos(45) Give Different Results
C++: Why Does Space Always Terminate a String When Read
Is There Any Danger in Calling Free() or Delete Instead of Delete[]
Generate All Sequences of Bits Within Hamming Distance T
Initial Value of Reference to Non-Const Must Be an Lvalue