本サイトからスピンオフした姉妹サイトです。C#2016年4月7日C#の次バージョンに追加される「パターンマッチング」の挙動(パターンマッチングがどう展開されるのかや、その実現方法)について説明する。7のパターンマッチングについて、必要とされる背景や書き方について説明した。後編となる今回は、パターンマッチングがどう展開されるかなど、内部的な仕組みについて説明する。前編同様、リスト1に示す型を使って説明していく。サンプルとして使う型階層それでは、パターンマッチングの展開結果がどうなるかを説明していこう。位置指定パターンを除けば、パターンの展開結果はかなり簡単なものだ。パターンの展開結果まずは簡単なものから説明していく。型パターンとプロパティパターンを例に、パターンの展開結果を説明する。前編の型パターンの説明で「これまでas演算子とnullチェックを通して行っていた処理を簡素に書けるようになる」と書いたが、展開結果もまさにこの通りになる。リスト2に示すパターンの例を見てみよう。型パターンとプロパティパターンの例これは、リスト3のような処理に展開される。リスト2の展開結果この例を見ての通り、パターンマッチングは、as演算子以外は完全に静的な(=コンパイル時に型が確定している)処理である。as演算子のコストも十分小さく、実行性能的な心配は不要だろう。実行性能面で多少不利になる点を挙げると、case句が上から順に判定されることである。リスト3を見ての通り、1つ1つのcase句がifステートメントに置き換えられる。その結果、後ろに書いたcase句ほど、そこにたどり着くまでの負担が大きくなる。StudioなどのIDE上で、コード補完やハイライト(キーワードや型名の色付け表示)もかかる。位置指定パターンを実現するには一工夫挟む必要がある。現状、以下の3つの案が出ていて、確定はしていない。どれか1つに決まるという様子でもなく、複数に対応するかもしれない(=まずユーザー定義のis演算子があるかを調べて、あればそれを使い、なければ名前による自動対応を使うという可能性もある)。ユーザー定義のis演算子1つ目の案は位置指定パターンのために、ユーザー定義のis演算子を導入するというものだ。is演算子の例として、Constクラスに対する実装例をリスト4に示す。要は、位置指定パターンを実現するために新構文導入を導入する形だ。位置指定パターンは、このis演算子の呼び出しに展開される。この方法の場合、1つの型に対して複数のis演算子オーバーロードを実装することで、複数の分解方法を提供できる。問題は、実装の面倒くささだろう。Valueが必要になる。合計7回もvalue(もしくはValue)が出てくる。そこで、次回以降で説明するレコード型というものを使って、このis演算子も自動生成する予定である。リスト6のように書くだけで、リスト4のようなプロパティ、コンストラクター、is演算子が自動的に作られる。レコード型を使ってリスト4相当のコードを自動生成この仕組みが入った場合、リスト5のように複数のオーバーロードを追加したい場合にだけis演算子を定義することになるだろう。位置とプロパティの対応付け先ほどの例に表れたように、プロパティには同名のコンストラクター引数などを大量に必要とする場合がある。図1に示すように、コンストラクター引数とプロパティが1対1に対応する型を書く場面は多い。コンストラクター引数とプロパティが1対1に対応する型この場合、構築(コンストラクター呼び出し、オブジェクト初期化子)と分解(パターンマッチング)でも、引数の位置とプロパティ名に1対1の対応が付くことになる(図2)。match)ができれば、位置指定パターンをはじめ、いろいろなものが簡素に書け、便利になる。この対応付けにも2つの実装案がある。タプル型を返すGetValueメソッド1つ目は、明示的に対応付けを行うためのメソッドを書く方法である。第3回で説明したタプル型は、位置と名前の対応関係を最初から持っている。そこで、タプル型を返すようなGetValueというメソッド(拡張メソッドでも可)を1つ用意することで、位置とプロパティを対応付けようというものである。リスト7のような実装になる。位置指定パターンは、リスト8に示すようなコードに展開される。拡張メソッドも認めることで、自分以外の誰かが作った既存の型に対してGetValueメソッドを追加し、位置指定パターンなどの新機能に対応させることができる。一方でこの方法には、is演算子の場合と同様、プロパティ名と同じものを何度も書かざるを得ない面倒さという問題がある。is演算子同様、レコード型の場合は自動的に実装されることになるだろう。1つ、タプル型という別の新機能に依存するという問題がある。異なる機能の間の強い依存関係にはリスクがあり、可能ならば避けたいものである。それが検討途中の機能同士の間の依存関係となると、より一層のリスクとなるだろう。名前による対応ユーザー定義のis演算子でもタプル型を返すメソッドでも、面倒さに加えて、レコード型導入以前の既存の型に対して位置指定パターンを使えない(もしくは使えるようにするのに手間がかかる)という問題がある。実際のところ、図1に示したような、引数とプロパティが1対1に対応する型を書くことは非常に多い。リスト1に含まれる型も全てそうなっている。そこで、リスト9に示すように、「ConstクラスのValueプロパティは第1引数valueと対応している」というような、名前を見ての対応付けを自動的に行ってしまおうという発想が出てくる。名前を見て位置とプロパティを対応付けC#では、このように名前の一致を見て異なるものを同一視する機能を他に持っていない。いう意味ではかなり異色な機能になってしまいそうである。既存の型に対して追加の作業なしで位置とプロパティの対応付けを行うには他に現実的な方法がなさそうだ。位置指定パターン以外にも、位置とプロパティの対応付けによって実現できる機能がある。その代表例は以下の2つ機能で、いずれもimmutableな型を便利にするためのものである。immutableな型に対するオブジェクト初期化子with式immutableな型というのは、フィールドが全て読み取り専用(readonly修飾子付きのフィールドや、get-onlyなプロパティ)で、コンストラクター以外では値の書き換えを行わない型だ。リスト1のクラスは全てそうなっている。6までのC#では、何かと不便な点があった。immutableな型に対するオブジェクト初期化子immutableな型は、コンストラクター引数で値を渡して初期化する必要がある。後からのプロパティ書き換えはできない。オブジェクト初期化子は単なるプロパティの書き換えに展開されるため、immutableな型に対しては使えなかった。これに対して、位置とプロパティの対応付けができると、リスト10に例を示すように、オブジェクト初期化子を引数付きのコンストラクター呼び出しに変換することで、immutableな型に対しても使えるようになる。値を書き換えられないということは、一部分だけを書き換えたい場合でもいちいち新しいインスタンスを作る必要がある。この際、書き換えない値についてもコンストラクターに渡しなおす必要があり、プロパティ数が増えてくるとかなりの手間となる。そこで、リスト11に示すように、with式という新しい構文を追加して、書き換えたい値だけを新しい値に置き換え、その他の値はそのまま新しいインスタンスに渡せるようにする。with式を使って一部分だけ書き換え展開結果にあるWithメソッドについては、次回以降、レコード型と一緒に説明する。ここでも、どのプロパティがWithメソッドのどの引数に対応するのかを決定する手段が必要になる。まとめ今回はパターンマッチングの展開結果など、内部的な仕組みについて説明した。型パターンやプロパティパターンは単なるas演算子への展開で、それほど複雑なものではない。位置指定パターンには(コンストラクター引数などの)位置とプロパティとの間の対応関係を知る必要がある。位置指定パターンの実現にはいくつかの案が出ているが、大まかにいうと、レコード型という新しい型定義のための構文にサポートしてもらうか、「同名の引数とプロパティを同一視する」というような名前での対応付けを必要とする。レコード型は次回以降で説明するが、これも便利で面白い機能だ。名前による対応付けはこれまでのC#ではあまり採用されてこなかった方針となる。7で導入したいいくつかの構文を、レコード型導入以前の既存の型に対して実現するためには名前による対応付けが必要かもしれない。1.0がプレビュー版だった頃からC#によるプログラミング入門を公開していて、C#とともに今年で15年になる。最近の自己紹介は「C#でググれ」。※以下では、本稿の前後を合わせて5回分(第3回~第7回)のみ表示しています。INDEX]を参照してください。複数データをまとめるための言語機能、タプル型メソッドが複数の値を戻す場合など、複数のデータを緩くまとめて、扱いたい場合はよくある。C#の次バージョンではこれを簡潔に記述するための機構として「タプル型」が導入される。型に応じた分岐や型の分解機能、パターンマッチングオブジェクトの型を階層的に調べて分岐処理を行いたい場合がある。そのための機能として、C#の次バージョンでは「パターンマッチング」が追加される。パターンマッチングの内部的な仕組みC#の次バージョンに追加される「パターンマッチング」の挙動(パターンマッチングがどう展開されるのかや、その実現方法)について説明する。機能や構文ばかりが注目されるが、プログラミング言語ではパフォーマンスも重要だ。パフォーマンス向上に対する要求が高まってきた背景と、向上のための改善方法を説明。7以降で追加が検討されている新機能にも言及する。前編に続き、次期C#のパフォーマンス向上について解説。7以降での採用が予定もしくは検討されているパフォーマンス向上関連の新機能の内容を具体的に見ていこう。機械学習エンジニアを目指す人~初中級者のための技術情報サイトです。「機械学習&AI」「クラウド&ビッグデータ」「IoTデバイス」のネット記事情報を共有中。開発者のためのSlackチーム、作りました:「機械学習&AI」「クラウド&ビッグデータ」「IoTデバイス」のネット記事情報を共有中。2020最適なビューへの切り替えを推奨します:スマートフォン用表示に。