Null合体演算子

**null合体演算子**（ヌルがったいえんざんし、null coalescing operator）はC#やバージョン5.10以降のPerl、Swiftなど、いくつかのプログラミング言語に存在する、ある種の条件演算子で、Perlでは**Defined-or 演算子**と呼ばれる。エルビス演算子も参照。C言語の3項演算子 `?` `:` で表現すると `( (a != null) ? a : b )` というような意味のコードをより単純に書ける、一種の糖衣構文と見ることもできる。

## 例
### C#
C#ではnull合体演算子は`??`である。次のように用いる。


```csharp
possiblyNullValue ?? valueIfNull
```


例えば、ページのタイトルが存在しない場合に既定値として"Default Title"を設定したい場合には、以下の文を用いることができる。


```csharp
string pageTitle = suppliedTitle ?? "Default Title";
```


これは次のようなより冗長な表現の代わりとして用いることができる。

```csharp
string pageTitle = (suppliedTitle == null) ? "Default Title" : suppliedTitle;
```

あるいは

```csharp
string pageTitle;

if (suppliedTitle == null)
    pageTitle = "Default Title";
else
    pageTitle = suppliedTitle;
```

これら3つの表現は等価である。

この演算子は同じ式の中で複数回用いることができる。

```csharp
return some_Value ?? some_Value2 ?? some_Value3;
```
 
一度、非nullな値が設定されるか、最終値（nullであるかもしれないしnullでないかもしれない）にたどり着くと完了する。

### CFML
ColdFusion 11もしくは 4.1ではCFMLはnull合体演算子を三項演算子`?:`の一種としてサポートする。上述のC#の同様のものと機能的にも文法的にも等価である。以下がそのコード例である。

```cfm
possiblyNullValue ?: valueIfNull
```


### Perl
Perl（5.10以降）においてnull合体演算子は`//`であり、以下のようなPerlのコードで用いることができる。


```perl
$possibly_null_value // $value_if_null
```


*possibly_null_value*は*null*か*非null*か（もしくは、Perlにおいては*未定義*か*定義済み*か）評価される。評価に基づき、*possibly_null_value*がnullの場合には*value_if_null*が返され、そうでない場合は*possibly_null_value*が返される。三項演算子 (**<code>[[?:]]</code>**) がサポートされる言語における三項演算子と同様に動作する。上述のPerlのコードは三項演算子の以下の用法と等価である。

```perl
defined($possibly_null_value) ? $possibly_null_value : $value_if_null
```

この演算子の最も一般的に利用法は単なるnullチェックのためのコードを最小限にするためである。

ある種の非nullの値（Perlの場合、0と空文字列）を偽として取り扱う他の言語と同様に、論理和演算子"`||`"はnull合体演算子ではない。


```perl
DB<1> print 0 // 1       # null合体演算子
0
  DB<2> print 0 || 1       # null合体演算子ではない
1
```


Perlはさらに`//=`代入演算子を有し、
```perl
a //= b
```
は
```perl
a = a // b
```
とおおむね等価である。

### Swift

Swiftではnil合体演算子は`??`である。Optional型のアンラップの際のデフォルトを提供するために用いられている。


```swift
optionalValue ?? valueIfNil
```


例えば、ページのタイトルが存在しない場合にデフォルトとして"Default Title"を設定するSwiftのコードを実装したい場合には、以下の文を用いることができる。


```swift
var suppliedTitle: String? = ...
var pageTitle: String = suppliedTitle ?? "Default Title"
```


これは以下の冗長な文の代わりとなる。

```swift
var pageTitle: String = (suppliedTitle != nil) ? suppliedTitle! : "Default Title";
```


### SQL

OracleのPL/SQLでは()関数が同じ役割を提供する。

```plsql
NVL(possibly_null_value, 'value if null');
```


SQL Server/Transact-SQLでは同じパターンのISNULL関数が存在する。

```tsql
ISNULL(possibly_null_value, 'value if null');
```

*ISNULL*と*IS NULL*を混同しないように注意が必要である。後者は何かが*NULL*として宣言されているか否かを評価するために存在する。

ANSI SQL-92標準規格はOracle、SQL Server、PostgreSQL、SQLite、そしてMySQLに実装されているCOALESCE関数を含む。COALESCE関数はnullでない最初の引数を返し、すべての引数がnullの場合はnullを返す。

```sql
COALESCE(possibly_null_value[, possibly_null_value, ...]);
```


### PHP
PHPではPHP 7以降でnull合体演算子`??`を利用できる。


```php
$var = $foo ?? $bar ?? $foobar;
// これは以下と等価である。
$var = (isset($foo) ? $foo : (isset($bar) ? $bar : $foobar));
```


PHP 7でnull合体演算子`??`が追加される以前から、三項演算子として用いられる`?:`条件演算子の真ん中の部分を二項演算子を作るために除外することができた(PHP 5.3以降)。最初は関連した言語に登場したので、顔文字と似ていることから**エルビス演算子**としても知られている。

```php
$foo = $foo ? $foo : $bar;

$foo = $foo ?: $bar;
```



```php
return $foo ?: $bar;
```


しかし、PHPの文法上の不幸なエラーにより、三項の条件演算子はPHPにおいては期待される動作と違い左結合性であるため、 複数の条件演算子を組み合わせると極めて直感的でない結果となる。エルビス演算子は（三項演算子の場合と同様に）チェーン表記した際にこの文法上の制約にさらされる。


```php
// 以下は等価である。
$var =  $foo ? $bar : $bar  ?: $baz;
$var = ($foo ? $bar : $bar) ?: $baz;
$var =                $bar  ?: $baz;

// 期待される動作は括弧を用いることによって得られる。
$var = $foo ? $bar : ($bar ?: $baz);
```


`?:`演算子は、（他のいくつかのプログラミング言語でのnull合体演算子と同様に）最初の項が`TRUE`と評価されるときに最初の項を返す。また、最初の項に未定義の変数が与えられた場合にNOTICEレベルの警告を発生する。

一方、`??`演算子は未定義の変数を与えることができ、また、最初の項が`NULL`または未定義の変数でなければ、整数0や空の配列など`FALSE`と評価される値であっても最初の項を返す。この点において、演算子はPHPの`isset()`疑似関数と同様に振る舞う。

これらの演算子は、PHPにおける三項演算子の（通常の）用法と同様に、結果を変数に代入する代わりにechoやreturnにも用いることができる。


```php
echo   $foo ?? $bar;

echo   $foo ?: $bar;

return $foo ?? $bar;

return $foo ?: $bar;
```


### JavaScript
ECMAScript 2020でNull合体演算子がサポートされた。


```javascript
const a = b ?? 3;
```


## 他の演算子を使用しての再現

条件演算子やOR演算子などを用いることでnull合体演算子と同様の働きを再現させることができる言語も多い。
* エルビス演算子: エルビス演算子は本来はnullではなくfalseのチェックを行うものだが、nullをfalseとみなす言語が存在する。
* OR演算子: エルビス演算子と同様nullをfalseとみなす場合に、短絡評価の仕様を利用することで実現する
* カスタム演算子の定義

### Python
Pythonの`or`演算子は以下に示されるようにnull合体演算子ではない。

```python
>>> 0 or 1
1
```

もしも`or`がnull合体演算子であれば、最初のnullでない値である0を返すはずである（Pythonにおけるnullは`None`であるが、0とNoneは異なる値であり、式`0 is None`は偽となる）。しかしながら、実際には、`or`演算子は左項が0やFalseや空文字列でないことを保証するために（もしくはそれらをNoneと区別する必要性がない場合に）用いられることがある。

### Scheme
Schemeでは"偽"と"null"は`#f`と表記される同じ値で代表される。その上、0や空文字列や空リストが偽として振る舞う他の一部の言語と異なり、`#f`はSchemeの論理演算子で偽として評価される唯一の値である。`(or x y)`と表記される論理`or`演算子は、`x`が偽でない場合には`x`を返し、そうでない場合には`y`を返す。これにより、Schemeでは独立した「null合体演算子」を設ける必要性がなく、`or`がその目的を達成する。

### JavaScript（ECMAScript 2019以前）
ECMAScript 2019以前では、null合体演算子の役割は論理`or`演算子を用いることで達成されていた。

```javascript
function setTitle(suppliedTitle) {
    this.title = suppliedTitle || "Default title";
}
```


これはJavaScriptの真偽判定のコンセプト上の問題により、null合体の正しい例ではないことに注意が必要である。このため、JavaScriptが偽であると評価する値（例えば0や偽）も同様に文の評価において合体され、望ましくない結果をもたらす可能性がある。

### Kotlin

Kotlinはエルビス演算子`?:`を用いる。


```scala
val title = suppliedTitle ?: "Default title"
```


### Groovy

GroovyでもKotlinと同様にエルビス演算子を使用することができる。
エルビス演算子は本来はnullではなくfalseのチェックを行うものだが、これらの言語ではnullはfalseとみなされる。

### Objective-C

Objective-Cにおいてはnull合体演算子の役割は`?:`演算子における`?`の後の重複した値を単純に省略することによって達成される。


```objc
id valueOrNil = ...;
id nonNilValue = valueOrNil ?: @"Some Default Value";
```


**注意**：JavaScriptやPythonの場合と同様に、`int`や`BOOL`のようなプリミティブと用いた場合には偽として評価され、続く値が返されるため、これは「真の」null合体演算子ではない。さらに、この表記はLLVMコンパイラに追加されたCのGNU拡張であることにも注意が必要である。

### F#
nullはF#においては値や変数として通常用いられない。しかしながら、例えばF#のコードがC#から呼ばれるような場合にnullが登場する。

F#は組み込みのnull合体演算子を持っていないが、必要に応じてカスタムの演算子として定義することができる。


```fsharp
let (|?) lhs rhs = (if lhs = null then rhs else lhs)
```


このカスタムの演算子はC#の組み込みのnull合体演算子と同様に用いることができる。


```fsharp
let pageTitle = suppliedTitle |? "Default Title"
```


### Smalltalk
Smalltalkには演算子は存在せず専用の構文も存在しないが、関数呼び出しに相当するメッセージ式と無名関数に相当するブロックの組み合わせで同等の機能を実現している。
```smalltalk
value := value ifNil: [ 0 ].
```
なお、逆の式も存在する。
```smalltalk
value := value ifNotNil: [ 0 ].
```
ブロックと式の組み合わせであるため下記のように分離することもできる。

これは、ブロックを上位のメソッドから引数として受とる場合に役に立つ。
```smalltalk
block := [ :argument | 1 + argument ].
value := value ifNotNil: block.
```


## 関連項目
*演算子
*条件演算子: ` ? : `
*Null条件演算子: ` ?. `など
*エルビス演算子: ` ?: `

## 参考文献