The ?. get-member-if-not-null-or-undefined-else-bail


#1

Borrowing from a recent (well, 2014) C# 6.0 addition, the null propagation operator, I propose the get-member-if-not-null-or-undefined-else-bail syntax - ?., which can shorten a lot of code - return object?.member?.innerMember It is an almost* equivalent syntactic sugar for - return object && object.member && object.member.innerMember (*This obviously checks for more than just null or undefined and can be problematic, but authors generally knows they are dealing with members that are objects and not other truthy values)

Or the longer -

if (object)
{
 if (object.member)
 {
  return object.member.innerMember;
 }
}

#2

Nice idea. An alternative solution would be to have a sort of built-in function that would just suppress errors during trying to access submembers of its argument, for example:

lastObjectMember(object.member.innerMember);

#3

Kind of like the typeof magic (you can reference non existent variables in typeof, but using them otherwise, even in if (nonExistentVariable) would throw)? I think I prefer less magic…


#4

The trouble I have with this is that I’d want it to also apply with [] indexing (there are just as many constructions where this is useful for array indexing and/or variable indices), but parsing a partial construction like object?['member'/*...*/ would be syntactically ambiguous with value ? [array,members,ifTrue] : somethingElse without requiring a non-trivial amount of lookahead for a matching :, if I’m not mistaken.

Perhaps the operator could be .?property, and the matching indexing operator could be [?index] - just switching the character order from how C# did it?


#5

Yep, that looks great.


#6

It’s worth noting that the (non-magic) version of this is already simple enough to implement yourself, using a slightly different signature (assuming none of the properties have . in the name):

function lastObjectMember(node, route) {
  route = route.split('.');
  while (node !== null && node !== undefined && route.length) {
    node = node[route.shift()];
  }
  return node;
}

/* usage: */

lastObjectMember(object,'member.innerMember');

#7

Yes, but that adds a considerable amount of overhead.


#8

Eh, if you go one step further and change the signature to take a constructed array directly (and the implementation to use an iterator instead of shift()), it’s really not all that much more overhead than the logic that would be loaded by the VM - they’re both just a small constant stack allocation factor followed by an O(n) list traversal.


#9

I disagree. I do not think the virtual machine logic would add so much more overhead. It already does it with the && way. ?. will have even less checks to worry about. https://jsperf.com/member-null-checks shows a considerable difference.

Then again, I never built, developed or maintained a virtual machine. :slight_smile:


#10

Someone proposed it recently to TC39! Stage 1 (no GitHub explainer yet) -

Babel plugin (conforms to a different specification, though, but close) -