マクロはファーストクラスオブジェクト

Curlの掲示板に回答した内容をこっちにもコピペ。

まず質問の内容は、

・unsetは昔から{unset ***}と書かなければ正しく動作しないのか
・なぜ {}なしでエラーにならないのか

というもので、

unset a.enabled?

というように、{}をつけなくてもコンパイルエラーにならないのに、enabled?がunsetされないという疑問でした。確かに unset は{}を省略可能な set と名前的に対っぽく見えるので、同様に {} を省略できそうに思っても仕方ないかもしれませんが、実はだめなんです。

> ・unsetは昔から{unset ***}と書かなければ正しく動作しないのか
これはToonaさんも回答されてるように、昔から{}無しの書き方は
認められてないはず。
Curlは評価する全ての式を{}で囲むというシンプルな規則が基本で、
let, set, fieldなど(だけ?)が例外で{}を*省略可能*なのです。


> ・なぜ {}なしでエラーにならないのか
これはマクロ型とプリミティブ型の違いが分かると理解できます。
普段プログラミングするだけであれば両者の違いはほとんど意識する
必要はありませんが、
・マクロはCurlのファーストクラスオブジェクトである
・プリミティブはファーストクラスオブジェクトではない
という違いが実はあります。
ファーストクラスオブジェクトというのは聞きなれないかもしれませんが
要は、

let a = {Frame}

と書けるように、マクロ、つまりファーストクラスオブジェクトである unset も

let a = unset

と書けるということです。

{some-proc define-class} ||define-classはマクロ
や
{return if} ||ifもマクロ

はアリですが、

{some-proc and} ||andはプリミティブ
{return public} ||publicもプリミティブ

というのは、プリミティブ型がファーストクラスオブジェクトでないためエラーになります。

つまり、

> unset a.enabled?

がコンパイルエラーにならないのは、単にふたつのファーストクラスオブジェクトが
スペースで区切られて並べてあるだけであって、

{Frame} {Frame}

と書いても

Frame Frame

と書いてもコンパイルエラーにならないのと同じなわけです。

結局、だったらなんで unset をマクロにしたんだ、と思うかもしれませんが、
これはCurl言語のコアを小さくシンプルに保って拡張性を高くすることが目的
なんだと思います。実際3.0から4.0では unset 以外にも多くのプリミティブが
マクロで実装し直されてます。