今回は、コーディングする上では知らなくても大事には至りにくい、言語仕様に近い話です。
糖衣構文、ご存知でしょうか?
例えば、C#のforeach
文は、糖衣構文です。
await
文*1も、糖衣構文です。
C#でキーワード*2として指定されているものの多くは、糖衣構文です。
そんな糖衣構文について、まとめてみます。
なお、とりあえずC#について、という前提にします。
糖衣構文とは
Wikipediaによると、
糖衣構文(とういこうぶん、英: syntactic sugar)は、プログラミング言語において、読み書きのしやすさのために導入される書き方であり、複雑でわかりにくい書き方と全く同じ意味になるものを、よりシンプルでわかりやすい書き方で書くことができるもののことである。
とのことで、要するに簡単に書くために用意されている構文です。
例1
上でも書いたforeach
ですが、
//1~10を列挙 var list = Enumerable.Range(1, 10); int sum = 0; foreach(var value in list) { sum += value; } //sumは55
のように、リスト等に入った中身を順次取り出す構文です。
これは、コンパイルすると、
//1~10を列挙 var list = Enumerable.Range(1, 10); int sum = 0; var it = list.GetEnumerator(); while(it.MoveNext()) { sum += it.Current.Value; } //sumは55
のように、別のソースとして実行されます。
本来、リストの中身を最後まで取得するには、
- GetEnumeratorを使う
- whileの中でMoveNextを使う
という処理が必要*3ですが、糖衣構文としてforeach
が用意されていることから、複雑なことを考えずに、全研処理できます。
例2
リストの全件処理ぐらいなら、for
文を使えばできます。
例でも出したawait
は、非同期処理の待ち合わせに使います。
これも糖衣構文で、実際には、GetAwaiter
というメソッドが使われる等、いろいろ裏でやってくれます。
以下の記事に細かく書いてあります。(あまり理解できなかった)
非同期処理は、これまでイベント駆動(EAP)やタスク駆動(TAP)等の考え方があり、処理を組むためのお約束が多かったです。
async
、await
の登場により、連続の非同期タスク等も書きやすく読みやすくなりました。*4
糖衣構文のいいところ
なにより、難しい構文を覚えなくていい、というところに尽きます。
決まったやり方があるのは良いことですが、そのコピペは生産的な作業とは言えません。
やはり、簡単に書けることは簡単に書いて、その他の生産的な作業に注力すべきと言えます。
そういう意味で、糖衣構文のような仕組みを導入するのは、開発者の目線からすれば、とても良いです。
糖衣構文に限った話ではなく、ライブラリ等を用いてソースを削減するのも同様の目的です。
糖衣構文の難しいところ
糖衣構文は、上で書いたように、コンパイル時に別の処理に置き換えられます。
これは、書いた通りに動くわけではないということを意味します。
たとえば、
- foreach中にシーケンスの要素数が変わると処理が行えない
- yield return をtry finally 句に配置できない
等は、糖衣構文がコンパイル時に別構文に置き換えられるために、発生するものです。*5
知っておくと役に立つ(ときがあるかもしれない)
C#は特に、新たな構文等がよく追加されるように思います。
新たな構文には妙な制約があったりしますが、それは「実際にはどう処理されているのか」による制約だったりします。
プログラミング言語の裏側では、開発者が楽するための仕組みがいろいろあって、それが逆に制約になることもある、と知っておくと、助かることがあるかもしれません。