SE(たぶん)の雑感記

一応SEやっている筆者の思ったことを書き連ねます。会計学もやってたので、両方を生かした記事を書きたいと考えています。 でもテーマが定まってない感がすごい。

糖衣構文について

今回は、コーディングする上では知らなくても大事には至りにくい、言語仕様に近い話です。

糖衣構文、ご存知でしょうか?

例えば、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というメソッドが使われる等、いろいろ裏でやってくれます。

以下の記事に細かく書いてあります。(あまり理解できなかった)

非同期プログラミング - await による一時停止と再生

非同期処理は、これまでイベント駆動(EAP)やタスク駆動(TAP)等の考え方があり、処理を組むためのお約束が多かったです。
asyncawaitの登場により、連続の非同期タスク等も書きやすく読みやすくなりました。*4

糖衣構文のいいところ

なにより、難しい構文を覚えなくていい、というところに尽きます。

決まったやり方があるのは良いことですが、そのコピペは生産的な作業とは言えません。
やはり、簡単に書けることは簡単に書いて、その他の生産的な作業に注力すべきと言えます。

そういう意味で、糖衣構文のような仕組みを導入するのは、開発者の目線からすれば、とても良いです。

糖衣構文に限った話ではなく、ライブラリ等を用いてソースを削減するのも同様の目的です。

糖衣構文の難しいところ

糖衣構文は、上で書いたように、コンパイル時に別の処理に置き換えられます。

これは、書いた通りに動くわけではないということを意味します。

たとえば、

  • foreach中にシーケンスの要素数が変わると処理が行えない
  • yield return をtry finally 句に配置できない

等は、糖衣構文がコンパイル時に別構文に置き換えられるために、発生するものです。*5

知っておくと役に立つ(ときがあるかもしれない)

C#は特に、新たな構文等がよく追加されるように思います。
新たな構文には妙な制約があったりしますが、それは「実際にはどう処理されているのか」による制約だったりします。

プログラミング言語の裏側では、開発者が楽するための仕組みがいろいろあって、それが逆に制約になることもある、と知っておくと、助かることがあるかもしれません。

*1:asyncが付いている場合に限る

*2:キーワード:ソース上、特別な文として扱われるもの。同じ名前の変数等を書けない

*3:for文等を使わなければの話

*4:非同期処理が簡単になったわけではない。

*5:このあたりは、コンパイル時にチェックされたり、例外を発生させたりして、安全に処理されている