本サイトからスピンオフした姉妹サイトです。7」についての議論が進んでいる。その中で提案されている「式」に関する新機能を取り上げる。7として提案されている文法の中には大小さまざまなものがある。今回紹介するのはその中では小さめの機能になる。「式を増やす」という、利便性の向上を目的としたものである。これらには、表1に示すような性質がある。式とステートメントの性質C#における例をいくつか表2に示す。C#の式とステートメントの例ひと言でいうと、戻り値を返せるなら式になっている方が便利である。その結果、新しい言語ほど、ステートメントを減らして式を増やす傾向にある。関数型言語にカテゴライズされるようなプログラミング言語ではもともとその傾向が強かったが、近年ではどんなパラダイムの言語であろうと式を好むようになっている。6で、いくつか式として書けるものが増えている。いくつかの例を表3に挙げよう。7でも、式にできるものが増える予定である。式はどこにでも書けて便利と説明したが、その一方で、どこにでも書けすぎるために、読みづらいコードも書けてしまう。それを嫌って、式が増えることに抵抗を感じる開発者もいまだに見受けられる(ベテランの方に多い傾向に見える)。それでも、式しか書けない場所が多い以上、ステートメントとしてしか書けない構文が多いことはよくないというのが筆者の意見だ。嫌なコードを書けてしまう問題よりも、そもそも書く手段が全くないことの方が問題は大きい。「書けてしまうから嫌」というなら、ステートメントだってひどいものである。書く人が書けば、{}の入れ子でソースコードはどんどん右側にずれていく。例として、ちょっとした総当たり計算を挙げよう。少々懐かしいネタではあるが、「send+more=money」という覆面算を解く問題がはやったことがある。そのとき、クエリ式(他のプログラミング言語だと、リストモナドやリスト内包)を使ったものと、ステートメントを使ったものの比較がよく取り上げられた。クエリ式を使うと以下のように書ける。ステートメントで書くと以下のようになるだろう。{}を省略したり、無理やりインデントをなくしたりすれば多少はすっきりするが、コード成型ツールをかけるたびに再びこのインデントがかかったりする。{money}");}}}}}}}}}}}}}}}}}覆面算の解法をステートメントで記述したステートメントなら良いというものではない。「式は読みづらい」というのも、それは「式の書き方を知らないせい」ということだってある。やり玉に挙げられるのが条件演算子?:だが、これだって、以下のように書けば意外ときれいなものである。これなら、if-elseステートメントで書くほどのものではないだろう。7での提案についての話に入る。以下のようなものが提案されている。宣言式シーケンス式それぞれ説明していこう。throw1つ目は、例外のthrowを式にしようというものである。前述の通り、式にするためには戻り値が必要である。throwの戻り値がどうなるべきかという話に帰結する。throw式ここでまず思い起こしてほしいのは、戻り値の型によらず、throwステートメントをもってメソッドを抜けられるということである。以下のメソッドはいずれもコンパイルできる。}値を戻さずに、throwステートメントでメソッドを抜けるこのことから、例外のthrowは「どんな型にでも変換可能な型」を戻り値に持つと考えて差し支えない。この考え方を認めれば、これまでthrowステートメントだったものは、そのままでthrow式になる。throwが式になってうれしい場面は限られていて、以下の4つである。7では、この4カ所でのみ、throwを式として書けるようにする方向で検討が進んでいる。ちなみに、「どんな型にでも変換可能な型」を「bottom型」(最下部の型、全ての型の派生扱い)と呼ぶことがある。この逆は「どんな型からでも変換可能な型」で、「top型」(最上部の型、全ての型の基底扱い)と呼び、C#の場合はobject型がこれに当たる。throw式が返す値の型はobject型の対極ということになる。never型throw式から一歩進めて、「必ず例外をthrowするメソッドの戻り値」を考えてみよう。breakステートメントと同じ)性質がある。この性質はコンパイラーも理解していて、適切なコード診断をしてくれる。コンパイラーも理解していて、警告などを出す}throwステートメントより後ろは実行されないこれに対して、例外をthrowする部分をメソッドに切り出すことを考えよう。現状だと以下のようになる。NeverReturnメソッドは常に例外をthrowするメソッドなので、そのメソッド呼び出しから後ろは実行されないはずだが、コンパイラーにはそれが分からず、各種診断が働かない。コンパイラーにはそれを判断できない}NeverReruntメソッドは常に例外をthrowするが、コンパイラーにはそれが分からないこの問題の解決策として、「常に例外をthrowするから、そこから後ろは実行されない」ということを表す型が欲しい。いう型として、never型という提案が出ている。never型とは以下のようなものである。常に例外を返す式の戻り値を表す任意の型に変換可能この型を返すメソッドを呼び出すと、そこから後ろは実行されないこれを使うと、先ほどのコードは以下のように書き換えられる。ここが実行されないことを、コンパイラーが判断できる}メソッドの戻り値型がnever型であれば、そのメソッド呼び出しより後にあるコードは実行されないことが判断できる他のプログラミング言語では、ScalaがNothing型という名前で同様の型を持っている。C#への導入に当たっても、neverの他にbottom、nothingなどの名前が検討されたが、「後ろが実行されない」という性質が名前に現れるよう、neverが最有力となっている。never型の実現方法は2種類ある。voidのメソッドに、NeverReturnといったような名前の属性を付ける.NETランタイム側にnever型を表す特別な型を足してもらう1のやり方であれば、C#コンパイラーだけで完結していて、近い将来に実装できる可能性が高い。一方で、ジェネリックの変性に対応できないなどの問題があり、1の方式での実装は見送られることになりそうだ。従って2のやり方が有力ではあるが、これには.NETランタイムのレベルで手を入れる必要がある。.NETランタイム側にはこれよりも優先度の高いタスクが山積みで、never型の実装に取り掛かれるのはだいぶ先になるだろう。前節のthrow式だけでも十分な利便性を得られるということもあり、never型はしばらく日の目を見なさそうである。式形式のswitch(match式)続いてはswitchの式化だ。これまでのC#でも、if-elseステートメントやループに相当する処理を式で書ける構文がある。表4に示すように、条件演算子?:やLINQがそれに当たる。一方で、switch相当の式はこれまでのC#にはなかった。次回以降で説明するパターンマッチングが登場すると、switchの利用頻度が増えることが予想される。そこで、switch相当の式が提案されている。現状の最有力候補の文法例は以下のようになっている。他の候補としては、以下のような案が出ている。使うかどうか完備性このswitch式(あるいはmatch式)を導入するに当たって、問題となるのは値の「完備性」(completeness)である。ここでいう完備というのは、「全てのパターンを網羅している」というような意味である。C#は完備性のチェックが緩く、switch(今後導入されるswitch式に限らず、既存のswitchステートメントでも)を使う上でもたびたび問題となる。C#では、bool型はtrueもしくはfalseのいずれかの値しか取らない。かかわらず、以下のswitchステートメントはコンパイルエラーとなる。パスがあります」というエラーを起こす。そんなパターンは本来あり得ないはずである。bool型はtrueとfalseの2つの値で完備(全パターン網羅している)完備性のチェックが正しく機能していれば、上記のコードはコンパイルできるはず:コンパイルできないのは完備性のチェックが緩いからということだ。bool型以上に問題となるのは列挙型だろう。C#の列挙型は特に完備性のチェックが難しい。以下のようなコードを見てもらえれば、このことが分かるだろう。(Color)100;}C#の列挙型は完備性のチェックが難しい列挙型の定義時に用意したのとは別の値をいくらでも無制限に使えてしまうため、全パターンの網羅は不可能である。残念ながら、今のところこの完備性チェックの緩さは解決できず、default句を必ず書いてしのぐことになる。上記コードは以下のように書き直す必要がある。InvalidOperationException();}}xの値がtrue、false以外の場合は、何か問題となる操作が行われているswitch式の場合はどうだろうか。繰り返しになるが、式には戻り値が必須である。前節で説明した通り、throwも式になり戻り値を返せる(返したものと見なせる)ようになったので、これをさっそく使うことになる。InvalidOperationException());switch式内でthrow式を使うことで、式が必ず戻り値を持つようになるthrow式でごまかすのではなく、完備性チェック自体についても一応検討課題には挙がっている。bool型はともかく、列挙型への対応は難しそうだ。次の「式化」は、変数宣言である。expressions)というものが提案されている。以下のようなコードを書ける。x;宣言式の使用例(その1)Square関数は、宣言式を使ってローカル変数xを宣言すると共にその初期値をint.Parse(s)した上で、そのxの二乗を戻り値とする。要するに、ちょっとした一時変数を式の中で宣言でき、このためだけにステートメントを書く必要がなくなる。6向けに検討されていた。7以降に仕切り直すことになった。パターンマッチングが入る前には、以下のようなコードで宣言式が有用ではないかといわれていた。InvalidOperationException();}宣言式の使用例(その2)メソッドMは、xの実際の型に応じて、返す値が変わる。この用途での宣言式はパターンマッチングに置き換えられることになる。詳細は次回以降で説明するが、以下のように書けるようになるだろう。InvalidOperationException());パターンマッチング私見として、この他で有用と思われる用途は、outパラメーターと番兵型ループの2つである。表5にこれらの例を示そう。宣言式の主な用途この例を見てもらえれば、単に変数宣言ステートメントが1つ減るだけではないことが分かるだろう。従来の書き方では、型推論(varの利用)ができないのに対して、宣言式を使えばそれができる。変数のスコープも短くできる。var」)だけ先に実装するかもしれないそうだ。varのみとなるからである。varすら要らなくなる可能性がある。int.TryParseであれば、以下のようなコードが認められるようになるかもしれない。int.TryParse(s);タプル型の変数resultは、int.TryParseメソッドの戻り値とoutパラメーターの値を格納するあるいはパターンマッチングを使った以下のような書き方もできるようになるかもしれない。宣言式で定義した変数のスコープ宣言式では、変数のスコープは原則として、「直近のステートメント内」となる予定だ。以下のコードでは、3つのステートメント内のいずれにもxという変数があるが、それぞれ別の変数となる。「原則として」といったのは、if-elseステートメントだけ例外となるからだ。if-elseステートメントでは、ifの条件式内で宣言した変数は、if側のブロックでだけ使え、else側からは使えない。先ほど「パターンマッチングに置き換えられそう」だと言ってお見せした例をあらためて出すが、以下のようなコードを書きたくなることがあるだろう。InvalidOperationException();}宣言式の使用例(再掲)この例のように、ifごとに別スコープを持ちたいという要求の方が、elseも同スコープにする要求よりも多かったようだ。expressions)だ。名前が分かりづらい(将来的に名称変更の可能性も結構あると思われる)が、「1つの()内に、;区切りで複数の式を並べて、最後の式の値を返す」というものだ(名前から想像するかもしれないが、IEnumerableを返すような何かではない)。以下のようなコードを書ける。y;シーケンス式この構文は、要するにC言語のコンマ演算子相当の機能だ。区切り文字に,ではなく;を使うのは、パラメーターリストやタプル(次回以降で説明)との区別のためである。前節の通り、宣言式で定義した変数のスコープはかなり短い。そのため、このような1つの式内に複数の式を並べられる構文が必要になる。まとめ近年、プログラミング言語の構文はステートメントよりも式を好む傾向にある。C#もその例にもれず、どんどん式を増やしている。7では、以下のようなものが提案されている。宣言式シーケンス式これらには、パターンマッチングやタプルなど、他の構文との兼ね合いもあって、そちらが安定してから調整が入る可能性も高い。式が増えることによって、手短に書けるコードが増えるだろう。便利すぎることで1行に何でも詰め込んだようなひどいコードが生産されるという懸念もあるが、手短なコードを書く手段がないよりはいいだろう。1.0がプレビュー版だった頃からC#によるプログラミング入門を公開していて、C#とともに今年で15年になる。最近の自己紹介は「C#でググれ」。※以下では、本稿の前後を合わせて5回分(第1回~第5回)のみ表示しています。INDEX]を参照してください。日本を代表する「C#(でぐぐれ)」の人、岩永信之氏によるコラムが遂に登場。今回はオープンソースで開発が行われているC#と開発者の関わり方について。7」についての議論が進んでいる。その中で提案されている「式」に関する新機能を取り上げる。複数データをまとめるための言語機能、タプル型メソッドが複数の値を戻す場合など、複数のデータを緩くまとめて、扱いたい場合はよくある。C#の次バージョンではこれを簡潔に記述するための機構として「タプル型」が導入される。型に応じた分岐や型の分解機能、パターンマッチングオブジェクトの型を階層的に調べて分岐処理を行いたい場合がある。そのための機能として、C#の次バージョンでは「パターンマッチング」が追加される。パターンマッチングの内部的な仕組みC#の次バージョンに追加される「パターンマッチング」の挙動(パターンマッチングがどう展開されるのかや、その実現方法)について説明する。機械学習エンジニアを目指す人~初中級者のための技術情報サイトです。「機械学習&AI」「クラウド&ビッグデータ」「IoTデバイス」のネット記事情報を共有中。開発者のためのSlackチーム、作りました:「機械学習&AI」「クラウド&ビッグデータ」「IoTデバイス」のネット記事情報を共有中。2020最適なビューへの切り替えを推奨します:スマートフォン用表示に。