Safe navigation operator

Last updated

In object-oriented programming, the safe navigation operator (also known as optional chaining operator, safe call operator, null-conditional operator, null-propagation operator) is a binary operator that returns null if its first argument is null; otherwise it performs a dereferencing operation as specified by the second argument (typically an object member access, array index, or lambda invocation).

Contents

It is used to avoid sequential explicit null checks and assignments and replace them with method/property chaining. In programming languages where the navigation operator (e.g. ".") leads to an error if applied to a null object, the safe navigation operator stops the evaluation of a method/field chain and returns null as the value of the chain expression. It was first used by Groovy 1.0 in 2007 [1] and is currently supported in languages such as C#, [2] Swift, [3] TypeScript, [4] Ruby, [5] Kotlin, [6] Rust [7] and others. There is currently no common naming convention for this operator, but safe navigation operator is the most widely used term.

The main advantage of using this operator is that it avoids the pyramid of doom. Instead of writing multiple nested ifs, programmers can just use usual chaining, but add question mark symbols before dots (or other characters used for chaining).

While the safe navigation operator and null coalescing operator are both null-aware operators, they are operationally different.

Examples

Apex

Safe navigation operator examples: [8]

a[x]?.aMethod().aField// Evaluates to null if a[x] == nulla[x].aMethod()?.aField// returns null if a[x].aMethod() evaluates to nullStringprofileUrl=user.getProfileUrl()?.toExternalForm();return[SELECTNameFROMAccountWHEREId=:accId]?.Name;

C#

C# 6.0 and above have ?., the null-conditional member access operator (which is also called the Elvis operator by Microsoft and is not to be confused with the general usage of the term Elvis operator , whose equivalent in C# is ??, the null coalescing operator) and ?[], the null-conditional element access operator, which performs a null-safe call of an indexer get accessor. If the type of the result of the member access is a value type, the type of the result of a null-conditional access of that member is a nullable version of that value type. [9]

The following example retrieves the name of the author of the first article in an array of articles (provided that each article has an Author member and that each author has an Name member), and results in null if the array is null, if its first element is null, if the Author member of that article is null, or if the Name member of that author is null. Note that an IndexOutOfRangeException is still thrown if the array is non-null but empty (i.e. zero-length).

varname=articles?[0]?.Author?.Name;

Calling a lambda requires callback?.Invoke(), as there is no null-conditional invocation (callback?() is not allowed).

varresult=callback?.Invoke(args);

Clojure

Clojure doesn't have true operators in the sense other languages uses it, but as it interoperable with Java, and has to perform object navigation when it does, the some-> [10] macro can be used to perform safe navigation.

(some->article.author.name)

CoffeeScript

Existential operator: [11]

zip=lottery.drawWinner?().address?.zipcode

Crystal

Crystal supports the try safe navigation method [12]

name=article.try&.author.try&.name

Dart

Conditional member access operator: [13]

varname=article?.author?.name

Gosu

Null safe invocation operator: [14]

varname=article?.author?.name

The null-safe invocation operator is not needed for class attributes declared as Gosu Properties:

classFoo{var_bar:StringasBar}varfoo:Foo=null// the below will evaluate to null and not return a NullPointerExceptionvarbar=foo.Bar

Groovy

Safe navigation operator and safe index operator: [1] [15]

defname=article?.authors?[0].name

JavaScript

Added in ECMAScript 2020, the optional chaining operator provides a way to simplify accessing values through connected objects when it's possible that a reference or function may be undefined or null. [16]

constname=article?.authors?.[0]?.nameconstresult=callback?.()

It short-circuits the whole chain of calls on its right-hand side: in the following example, bar is not "accessed".

null?.foo.bar

Kotlin

Safe call operator: [6]

valname=article?.author?.name

Objective-C

Normal navigation syntax can be used in most cases without regarding NULLs, as the underlying messages, when sent to NULL, is discarded without any ill effects.

NSString*name=article.author[0].name;

Perl 5

Perl 5 does not have this kind of operator, but a proposal for inclusion was accepted with the following syntax: [17]

my$name=$article?->author?->name;

PHP

The null safe operator was accepted for PHP 8: [18]

$name=$article?->author?->name;

Raku (Perl 6)

Safe method call: [19]

my$name = $article.?author.?name; 

Ruby

Ruby supports the &. safe navigation operator (also known as the lonely operator) since version 2.3.0: [5]

name=article&.author&.name

Rust

Rust provides a ? operator [7] that can seem like a safe navigation operator. However, a key difference is that when ? encounters a None value, it doesn't evaluate to None. Instead, it behaves like a return statement, causing the enclosing function or closure to immediately return None.

The Option methods map() and and_then() can be used for safe navigation, but this option is more verbose than a safe navigation operator:

fnprint_author(article: Option<Article>){println!("Author: {}",article.and_then(|y|y.author).map(|z|z.name).unwrap_or("Unknown".to_owned()));}

An implementation using ? will print nothing (not even "Author:") if article is None or article.unwrap().author is None. As soon as ? sees a None, the function returns.

fntry_print_author(article: Option<Article>)-> Option<()>{println!("Author: {}",article?.author?.name);Some(())}

Scala

The null-safe operator in Scala is provided by the library Dsl.scala. [20] [21]

valname=article.?.author.?.name:@?

The @ ? annotation can be used to denote a nullable value.

caseclassTree(left:Tree@?=null,right:Tree@?=null,value:String@?=null)valroot:Tree@?=Tree(left=Tree(left=Tree(value="left-left"),right=Tree(value="left-right")),right=Tree(value="right"))

The normal . in Scala is not null-safe, when performing a method on a null value.

a[NullPointerException]shouldbethrownBy{root.right.left.right.value// root.right.left is null!}

The exception can be avoided by using ? operator on the nullable value instead:

root.?.right.?.left.?.valueshouldbe(null)

The entire expression is null if one of ? is performed on a null value.

The boundary of a null safe operator ? is the nearest enclosing expression whose type is annotated as @ ?.

("Hello "+("world "+root.?.right.?.left.?.value))shouldbe("Hello world null")("Hello "+(("world "+root.?.right.?.left.?.value.?):@?))shouldbe("Hello null")(("Hello "+("world "+root.?.right.?.left.?.value.?)):@?)shouldbe(null)

Swift

Optional chaining operator, [3] subscript operator, and call:

letname=article?.authors?[0].nameletresult=protocolVar?.optionalRequirement?()

TypeScript

Optional chaining operator was included in the Typescript 3.7 release: [4]

letx=foo?.bar?.[0]?.baz();

Visual Basic .NET

Visual Basic 14 and above have the ?. (the null-conditional member access operator) and ?() (the null-conditional index operator), similar to C#. They have the same behavior as the equivalent operators in C#. [22]

The following statement behaves identically to the C# example above.

Dimname=articles?(0)?.Author?.Name

See also

Related Research Articles

In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function together with an environment. The environment is a mapping associating each free variable of the function with the value or reference to which the name was bound when the closure was created. Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.

In computer programming, the ternary conditional operator is a ternary operator that is part of the syntax for basic conditional expressions in several programming languages. It is commonly referred to as the conditional operator, ternary if, or inline if. An expression a ? b : c evaluates to b if the value of a is true, and otherwise to c. One can read it aloud as "if a then b otherwise c". The form a ? b : c is by far and large the most common, but alternative syntaxes do exist; for example, Raku uses the syntax a ?? b !! c to avoid confusion with the infix operators ? and !, whereas in Visual Basic .NET, it instead takes the form If(a, b, c).

This article compares two programming languages: C# with Java. While the focus of this article is mainly the languages and their features, such a comparison will necessarily also consider some features of platforms and libraries. For a more detailed comparison of the platforms, see Comparison of the Java and .NET platforms.

<span class="mw-page-title-main">Java syntax</span> Set of rules defining correctly structured program

The syntax of Java is the set of rules defining how a Java program is written and interpreted.

<span class="mw-page-title-main">Scala (programming language)</span> General-purpose programming language

Scala is a strong statically typed high-level general-purpose programming language that supports both object-oriented programming and functional programming. Designed to be concise, many of Scala's design decisions are intended to address criticisms of Java.

<span class="mw-page-title-main">JavaScript syntax</span> Set of rules defining correctly structured programs

The syntax of JavaScript is the set of rules that define a correctly structured JavaScript program.

<span class="mw-page-title-main">Oxygene (programming language)</span> Object Pascal-based programming language

Oxygene is a programming language developed by RemObjects Software for Microsoft's Common Language Infrastructure, the Java Platform and Cocoa. Oxygene is based on Delphi's Object Pascal, but also has influences from C#, Eiffel, Java, F# and other languages.

A delegate is a form of type-safe function pointer used by the Common Language Infrastructure (CLI). Delegates specify a method to call and optionally an object to call the method on. Delegates are used, among other things, to implement callbacks and event listeners. A delegate object encapsulates a reference to a method. The delegate object can then be passed to code that can call the referenced method, without having to know at compile time which method will be invoked.

Haxe is a high-level cross-platform programming language and compiler that can produce applications and source code for many different computing platforms from one code-base. It is free and open-source software, released under the MIT License. The compiler, written in OCaml, is released under the GNU General Public License (GPL) version 2.

A property, in some object-oriented programming languages, is a special sort of class member, intermediate in functionality between a field and a method. The syntax for reading and writing of properties is like for fields, but property reads and writes are (usually) translated to 'getter' and 'setter' method calls. The field-like syntax is easier to read and write than many method calls, yet the interposition of method calls "under the hood" allows for data validation, active updating, or implementation of what may be called "read-only fields".

In software engineering, a fluent interface is an object-oriented API whose design relies extensively on method chaining. Its goal is to increase code legibility by creating a domain-specific language (DSL). The term was coined in 2005 by Eric Evans and Martin Fowler.

The null coalescing operator is a binary operator that is part of the syntax for a basic conditional expression in several programming languages, including C# as of version 2.0, PowerShell as of version 7.0.0, Perl as of version 5.10, Swift, and PHP 7.0.0. While its behavior differs between implementations, the null coalescing operator generally returns the result of its left-most operand if it exists and is not null, and otherwise returns the right-most operand. This behavior allows a default value to be defined for cases where a more specific value is not available.

This article describes the syntax of the C# programming language. The features described are compatible with .NET Framework and Mono.

The syntax and semantics of PHP, a programming language, form a set of rules that define how a PHP program can be written and interpreted.

<span class="mw-page-title-main">ParaSail (programming language)</span>

Parallel Specification and Implementation Language (ParaSail) is an object-oriented parallel programming language. Its design and ongoing implementation is described in a blog and on its official website.

In object-oriented programming, method cascading is syntax which allows multiple methods to be called on the same object. This is particularly applied in fluent interfaces.

Kotlin is a cross-platform, statically typed, general-purpose high-level programming language with type inference. Kotlin is designed to interoperate fully with Java, and the JVM version of Kotlin's standard library depends on the Java Class Library, but type inference allows its syntax to be more concise. Kotlin mainly targets the JVM, but also compiles to JavaScript or native code via LLVM. Language development costs are borne by JetBrains, while the Kotlin Foundation protects the Kotlin trademark.

In certain computer programming languages, the Elvis operator, often written ?:, is a binary operator that returns its first operand if that operand evaluates to a true value, and otherwise evaluates and returns its second operand. This is identical to a short-circuit or with "last value" semantics. The notation of the Elvis operator was inspired by the ternary conditional operator, ? :, since the Elvis operator expression A ?: B is approximately equivalent to the ternary conditional A ? A : B.

Swift is a high-level general-purpose, multi-paradigm, compiled programming language developed by Apple Inc. and the open-source community. Swift compiles to machine code, as it is an LLVM-based compiler. Swift was first released in June 2014, and the Swift toolchain has shipped in Xcode since version 6, released in 2014.

In computer programming, the pyramid of doom is a common problem that arises when a program uses many levels of nested indentation to control access to a function. It is commonly seen when checking for null pointers or handling callbacks. Two examples of the term are related to a particular programming style in JavaScript, and the nesting of if statements that occurs in object-oriented programming languages when one of the objects may be a null pointer.

References

  1. 1 2 "Support the optional path operator (?.)". GitHub . Retrieved 2021-01-04.
  2. "Null-conditional Operators (C# and Visual Basic)" . Retrieved 2016-01-28.
  3. 1 2 "Optional Chaining" . Retrieved 2016-01-28.
  4. 1 2 "Typescript 3.7" . Retrieved 2019-11-06.
  5. 1 2 "Ruby 2.3.0 Released" . Retrieved 2016-01-28.
  6. 1 2 "Null Safety" . Retrieved 2016-01-28.
  7. 1 2 "The question mark operator, ?" . Retrieved 2021-10-04.
  8. "Salesforce Winter 21 Release Notes". Salesforce . Retrieved 2020-10-13.
  9. "Member access operators (C# reference)". Microsoft Docs. Microsoft. Retrieved 29 August 2019.
  10. "Threading Macros Guide" . Retrieved 2019-06-07.
  11. "The Existential Operatior" . Retrieved 2017-06-15.
  12. "Crystal API: Object#try".
  13. "Other Operators". A tour of the Dart language. Retrieved 2020-01-08.
  14. "The Gosu Programming Language" . Retrieved 2018-12-18.
  15. "8.5. Safe index operator" . Retrieved 2020-09-25.
  16. "Optional Chaining".
  17. "PPC 21 -- Optional Chaining". GitHub .
  18. "PHP: rfc:nullsafe_operator". wiki.php.net. Retrieved 2020-10-01.
  19. "Raku Operators" . Retrieved 2022-09-16.
  20. A framework to create embedded Domain-Specific Languages in Scala: ThoughtWorksInc/Dsl.scala, ThoughtWorks Inc., 2019-06-03, retrieved 2019-06-03
  21. "NullSafe: Kotlin / Groovy flavored null-safe ? operator now in Scala". Scala Users. 2018-09-12. Retrieved 2019-06-03.
  22. "?. and ?() null-conditional operators (Visual Basic)". Microsoft Docs. Microsoft. Retrieved 29 August 2019.