{{Short description|Boolean operator}} {{more citations needed|date=January 2016}} 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).

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<ref name="6.1. Safe navigation operator">{{cite web |url=https://github.com/apache/groovy/commit/f223c9b3322fef890c6db261720f703394c7cf27 |title=Support the optional path operator (?.) |website=GitHub |accessdate=2021-01-04}}</ref> and is currently supported in languages such as C#,<ref>{{cite web |url=https://msdn.microsoft.com/en-us/library/dn986595.aspx |title=Null-conditional Operators (C# and Visual Basic) |accessdate=2016-01-28}}</ref> Swift,<ref name="Optional Chaining">{{cite web |url=https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html |title=Optional Chaining|accessdate=2016-01-28}}</ref> TypeScript,<ref name="TypeScript - Optional Chaining"/> Ruby,<ref name="Ruby 2.3.0 Released">{{cite web |url=https://www.ruby-lang.org/en/news/2015/12/25/ruby-2-3-0-released/ |title=Ruby 2.3.0 Released |accessdate=2016-01-28}}</ref> Kotlin,<ref name="Null Safety">{{cite web |url=https://kotlinlang.org/docs/reference/null-safety.html |title=Null Safety |accessdate=2016-01-28}}</ref> Rust,<ref name="Rust - QuestionMarkOperator"/> JavaScript,<ref name="MDN - optional chaining in JavaScript">{{cite web |url=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining |title=MDN - optional chaining in JavaScript |date=28 October 2024 }}</ref> 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 <code>if</code>s, 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 in Apex:<ref>{{Cite web|last=|first=|date=|title=Salesforce Winter 21 Release Notes|url=https://releasenotes.docs.salesforce.com/en-us/winter21/release-notes/rn_apex_SafeNavigationOperator.htm|archive-url=|archive-date=|access-date=2020-10-13|website=Salesforce}}</ref><syntaxhighlight lang="java"> a[x]?.aMethod().aField // Evaluates to null if a[x] == null a[x].aMethod()?.aField // returns null if a[x].aMethod() evaluates to null String profileUrl = user.getProfileUrl()?.toExternalForm(); return [SELECT Name FROM Account WHERE Id = :accId]?.Name; </syntaxhighlight>

===C#=== C# 6.0 and above have <code>?.</code>, 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 <code>??</code>, the null coalescing operator) and <code>?[]</code>, 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.<ref>{{cite web |title=Member access operators (C# reference) |url=https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and- |website=Microsoft Docs |publisher=Microsoft |accessdate=29 August 2019}}</ref>

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

<syntaxhighlight lang="csharp"> string name = articles?[0]?.Author?.Name; </syntaxhighlight>

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

<syntaxhighlight lang="csharp"> Func<int, int> callback = x => x * x; // squares x int result = callback?.Invoke(5); </syntaxhighlight>

=== 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 <code>some-></code><ref>{{cite web |url=https://clojure.org/guides/threading_macros#_some_some_and_cond |title=Threading Macros Guide |accessdate=2019-06-07}}</ref> macro can be used to perform safe navigation. An extended macro <code>safe-></code><ref>{{cite web|url=https://gist.github.com/shaunlebron/0950a2a2e65beec6c121dff3de6309f1 |title=Safe Navigation in Clojure |accessdate=2025-11-05}}</ref> prevents calling nil values.

<syntaxhighlight lang="clojure">(some-> article .author .name)</syntaxhighlight>

===CoffeeScript=== Existential operator:<ref>{{cite web |url=http://coffeescript.org/#existential-operator |title=The Existential Operatior |accessdate=2017-06-15}}</ref> <syntaxhighlight lang="coffeescript">zip = lottery.drawWinner?().address?.zipcode</syntaxhighlight>

===Crystal=== Crystal supports the <code>try</code> safe navigation method <ref>{{cite web |title=Crystal API: Object#try |url=https://crystal-lang.org/api/0.27.0/Object.html#try%28%26block%29-instance-method}}</ref>

<syntaxhighlight lang="crystal">name = article.try &.author.try &.name</syntaxhighlight>

=== Dart === Conditional member access operator:<ref name=":0">{{Cite web|url=https://dart.dev/guides/language/language-tour#other-operators|title=Other Operators|last=|first=|date=|website=A tour of the Dart language|archive-url=|archive-date=|access-date=2020-01-08}}</ref><syntaxhighlight lang="dart">var name = article?.author?.name</syntaxhighlight>

===Gosu=== Null safe invocation operator:<ref>{{cite web |url=https://gosu-lang.github.io/docs.html |title=The Gosu Programming Language |accessdate=2018-12-18}}</ref>

<syntaxhighlight lang="gosu">var name = article?.author?.name</syntaxhighlight>

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

<syntaxhighlight lang="gosu">class Foo { var _bar: String as Bar }

var foo: Foo = null

// the below will evaluate to null and not return a NullPointerException var bar = foo.Bar</syntaxhighlight>

===Groovy=== Safe navigation operator and safe index operator:<ref name="6.1. Safe navigation operator"/><ref>{{cite web |url=http://www.groovy-lang.org/operators.html#_safe_navigation_operator |title=8.5. Safe index operator |accessdate=2020-09-25}}</ref>

<syntaxhighlight lang="groovy"> def name = article?.authors?[0].name </syntaxhighlight>

=== 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''.<ref>{{Cite web|url=https://tc39.es/proposal-optional-chaining/|title = Optional Chaining in ECMAScript 2020}}</ref> Major desktop browsers have supported this since 2020, and most mobile browsers added support by 2024.<ref>{{Cite web|url=https://caniuse.com/mdn-javascript_operators_optional_chaining|title = Browser Support for Optional Chaining in JavaScript}}</ref> <syntaxhighlight lang="javascript"> const name = article?.authors?.[0]?.name const result = callback?.() </syntaxhighlight>

It short-circuits the whole chain of calls on its right-hand side: in the following example, ''bar'' is not "accessed". <syntaxhighlight lang="javascript"> null?.foo.bar </syntaxhighlight>

===Kotlin=== Safe call operator:<ref name="Null Safety"/>

<syntaxhighlight lang="kotlin">val name = article?.author?.name</syntaxhighlight>

===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. <syntaxhighlight lang="objc">NSString *name = article.author[0].name;</syntaxhighlight>

=== Perl 5 === Perl 5 does not have this kind of operator, but a proposal for inclusion was accepted with the following syntax:<ref>{{cite web|title=PPC 21 -- Optional Chaining|website=GitHub |url=https://github.com/Perl/PPCs/blob/main/ppcs/ppc0021-optional-chaining-operator.md}}</ref> <syntaxhighlight lang="perl">my $name = $article?->author?->name;</syntaxhighlight>

=== PHP === The null safe operator was accepted for PHP 8:<ref>{{Cite web|title=PHP: rfc:nullsafe_operator|url=https://wiki.php.net/rfc/nullsafe_operator|access-date=2020-10-01|website=wiki.php.net}}</ref>

<syntaxhighlight lang="php">$name = $article?->author?->name;</syntaxhighlight>

===Raku (Perl 6)=== Safe method call:<ref>{{cite web |url=https://docs.raku.org/language/operators#methodop_.? |title=Raku Operators |accessdate=2022-09-16}}</ref>

<syntaxhighlight lang="pl6">my $name = $article.?author.?name;</syntaxhighlight>

===Ruby=== Ruby supports the <code>&.</code> safe navigation operator (also known as the ''lonely operator'') since version 2.3.0:<ref name="Ruby 2.3.0 Released"/>

<syntaxhighlight lang="ruby">name = article&.author&.name</syntaxhighlight>

===Rust=== Rust provides a <code>?</code> operator<ref name="Rust - QuestionMarkOperator">{{cite web | url=https://doc.rust-lang.org/std/result/index.html#the-question-mark-operator-|title=The question mark operator, ?|accessdate=2021-10-04}}</ref> that can seem like a safe navigation operator. However, a key difference is that when <code>?</code> encounters a <code>None</code> value, it doesn't evaluate to <code>None</code>. Instead, it behaves like a <code>return</code> statement, causing the enclosing function or closure to immediately return <code>None</code>.

The <code>Option</code> methods <code>map()</code> and <code>and_then()</code> can be used for safe navigation, but this option is more verbose than a safe navigation operator: <syntaxhighlight lang="rust"> fn print_author(article: Option<Article>) { println!( "Author: {}", article.and_then(|y| y.author) .map(|z| z.name) .unwrap_or("Unknown".to_owned()) ); } </syntaxhighlight>

An implementation using <code>?</code> will print nothing (not even "Author:") if <code>article</code> is <code>None</code> or <code>article.unwrap().author</code> is <code>None</code>. As soon as <code>?</code> sees a <code>None</code>, the function returns. <syntaxhighlight lang="rust"> fn try_print_author(article: Option<Article>) -> Option<()>{ println!("Author: {}", article?.author?.name); Some(()) } </syntaxhighlight>

=== Scala ===

The null-safe operator in Scala is provided by the library Dsl.scala.<ref>{{Citation |title=A framework to create embedded Domain-Specific Languages in Scala: ThoughtWorksInc/Dsl.scala |date=2019-06-03 |url=https://github.com/ThoughtWorksInc/Dsl.scala |access-date=2019-06-03 |publisher=ThoughtWorks Inc.}}</ref><ref>{{Cite web|url=https://users.scala-lang.org/t/nullsafe-kotlin-groovy-flavored-null-safe-operator-now-in-scala/3244|title=NullSafe: Kotlin / Groovy flavored null-safe ? operator now in Scala|date=2018-09-12|website=Scala Users|language=en|access-date=2019-06-03}}</ref>

<syntaxhighlight lang="scala">val name = article.?.author.?.name : @ ?</syntaxhighlight>

The <code>@ ?</code> annotation can be used to denote a nullable value.

<syntaxhighlight lang="scala">case class Tree(left: Tree @ ? = null, right: Tree @ ? = null, value: String @ ? = null)

val root: Tree @ ? = Tree( left = Tree( left = Tree(value = "left-left"), right = Tree(value = "left-right") ), right = Tree(value = "right") )</syntaxhighlight>

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

<syntaxhighlight lang="scala">a[NullPointerException] should be thrownBy { root.right.left.right.value // root.right.left is null! }</syntaxhighlight>

The exception can be avoided by using <code>?</code> operator on the nullable value instead:

<syntaxhighlight lang="scala">root.?.right.?.left.?.value should be(null)</syntaxhighlight>

The entire expression is <code>null</code> if one of <code>?</code> is performed on a <code>null</code> value.

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

<syntaxhighlight lang="scala">("Hello " + ("world " + root.?.right.?.left.?.value)) should be("Hello world null") ("Hello " + (("world " + root.?.right.?.left.?.value.?): @ ?)) should be("Hello null") (("Hello " + ("world " + root.?.right.?.left.?.value.?)): @ ?) should be(null)</syntaxhighlight>

===Swift=== Optional chaining operator,<ref name="Optional Chaining"/> subscript operator, and call:<syntaxhighlight lang=Swift> let name = article?.authors?[0].name let result = protocolVar?.optionalRequirement?() </syntaxhighlight>

===TypeScript=== Optional chaining operator was included in the TypeScript 3.7 release:<ref name="TypeScript - Optional Chaining">{{cite web |url=https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html |title=Typescript 3.7 |accessdate=2019-11-06}}</ref> <syntaxhighlight lang="typescript">let x = foo?.bar?.[0]?.baz();</syntaxhighlight>

===Visual Basic .NET=== Visual Basic 14 and above have the <code>?.</code> (the ''null-conditional member access operator'') and <code>?()</code> (the ''null-conditional index operator''), similar to C#. They have the same behavior as the equivalent operators in C#.<ref>{{cite web |title=?. and ?() null-conditional operators (Visual Basic) |url=https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/null-conditional-operators |website=Microsoft Docs |publisher=Microsoft |accessdate=29 August 2019}}</ref>

The following statement behaves identically to the C# example above. <syntaxhighlight lang="vbnet">Dim name = articles?(0)?.Author?.Name</syntaxhighlight>

==See also== *Elvis operator *Null coalescing operator

==References== {{Reflist}}

==External links== * [https://www.python.org/dev/peps/pep-0505/ PEP 505], discussing the possibility of safe navigation operators for Python

Category:Operators (programming) Category:Conditional constructs Category:Articles with example code Category:Object-oriented programming