Null合体演算子

出典: フリー百科事典『ウィキペディア(Wikipedia)』
移動先: 案内検索

null合体演算子 (null coalescing operator)はC#[1]や5.10以降のPerl[2]Swift[3]など、いくつかのプログラミング言語における基本的な条件表現の文法の一種である。PerlではDefined-or 演算子と呼ばれる。

[編集]

C#[編集]

C#ではnull合体演算子は??である。null表現を簡略化するために次のように用いられることが多い。

possiblyNullValue ?? valueIfNull

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

string pageTitle = suppliedTitle ?? "Default Title";

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

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

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

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

この演算子は同じ表現内で複数回用いることが出来る。

return some_Value ?? some_Value2 ?? some_Value3;

一度、非nullな値が設定されるか、最終値(nullであるかもしれないしnullでないかもしれない)にたどり着くと完了する。

CFML[編集]

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

possiblyNullValue ?: valueIfNull

Perl[編集]

Perl(5.10以降)においてnull合体演算子は//であり、以下のようなPerlのコードで用いることが出来る。

$possibly_null_value // $value_if_null

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

defined($possibly_null_value) ? $possibly_null_value : $value_if_null

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

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

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

Perlはさらに//=代入演算子を有し、

a //= b

a = a // b

とおおむね等価である。

Swift[編集]

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

optionalValue ?? valueIfNil

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

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

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

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

SQL[編集]

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

NVL(possibly_null_value, 'value if null');

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

ISNULL(possibly_null_value, 'value if null');

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

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

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

PHP[編集]

PHPではPHP 7以降でnull合体演算子??を利用できる[11]

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

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

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

$foo = $foo ?: $bar;
return $foo ?: $bar;

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

// 以下は等価である。
$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における三項演算子の(通常の)用法と同様に、結果を変数に代入する代わりにechoreturnにも用いることができる。

echo   $foo ?? $bar;

echo   $foo ?: $bar;

return $foo ?? $bar;

return $foo ?: $bar;

他の演算子を使用しての再現[編集]

条件演算子やOR演算子などを用いることでnull合体演算子と同様の働きを再現させることができる言語も多い。

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

Python[編集]

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

>>> 0 or 1
1

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

Scheme[編集]

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

JavaScript[編集]

JavaScriptではnull合体演算子の役割は論理or演算子を用いることで達成される。

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

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

Kotlin[編集]

Kotlinエルビス演算子?:を用いる[17]

val title = suppliedTitle ?: "Default title"

Groovy[編集]

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


Objective-C[編集]

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

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

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

F#[編集]

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

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

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

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

let pageTitle = suppliedTitle |? "Default Title"


関連項目[編集]

参考文献[編集]

  1. ^ ?? 演算子 (C# リファレンス)
  2. ^ // Operator (Perl Reference)
  3. ^ Nil Coalescing Operator
  4. ^ Elvis operator
  5. ^ RAILO-2195 add support for the Elvis Operator
  6. ^ http://docs.oracle.com/cd/B28359_01/server.111/b28286/functions023.htm#SQLRF00617
  7. ^ http://technet.microsoft.com/en-us/library/ms174075.aspx
  8. ^ http://www.postgresql.org/docs/9.1/static/functions-conditional.html#FUNCTIONS-COALESCE-NVL-IFNULL
  9. ^ http://www.sqlite.org/lang_corefunc.html
  10. ^ http://dev.mysql.com/doc/refman/5.5/en/comparison-operators.html#function_coalesce
  11. ^ a b PHP: 比較演算子”. 2016年10月21日閲覧。
  12. ^ coding style - ?: operator PHP”. 2014年2月17日閲覧。
  13. ^ https://github.com/getrailo/railo/wiki/Operators#elvis-operator
  14. ^ coding style - ?: operator”. Stack Overflow. 2014年2月17日閲覧。
  15. ^ Joyce Farrell. Java Programming. p. 276. ISBN 978-1285081953. "The new operator is called Elvis operator because it uses a question mark and a colo together (?:)" 
  16. ^ PHP Bug #61915: incorrect associativity of ternary operator”. PHP website (2012年5月2日). 2014年2月17日閲覧。
  17. ^ Null Safety”. 2015年1月17日閲覧。
  18. ^ Operators - Groovy”. 2015年1月17日閲覧。
  19. ^ null 値 (F#)
  20. ^ 演算子のオーバーロード (F#)