読者です 読者をやめる 読者になる 読者になる

この日記は私的なものであり、所属会社の見解ではありません。 GitHub: takahashikzn

#defineはダイナミック。

Java

Apache Velocity。とてもよく出来ているマクロプロセッサです。


個人的に昔から(version1.2あたりから)ずっと愛用している逸品でして、
弊社製品MOD99でも、内部でコレデモカと使いまくってます。

黒歴史

昔、Velocityのソースを魔改造して独自プログラミング言語を作ったことがあります。
カリー化とか高階関数とか、その当時流行った要素を詰め込みまくった「オレオレ言語」だったなぁ。。。( ゚д゚)
いまとなっては黒歴史なダケなんだけど。


その当時、JavaCCの本を買って勉強したものです(VelocityのパーザはJavaCCで書かれている)
JavaCC関連の和書はコレしかない模様。

JavaCC―コンパイラ・コンパイラfor Java

JavaCC―コンパイラ・コンパイラfor Java

文章の言い回しとか章立てとか、ほとんど大学の情報処理系の教科書を読んでいるような感覚。
(まぁ、筆者の方は法政大学の教授なので当然なんだけど)
なんだがとても懐かしい気分に浸れたましたが、とりあえずコンパイラとか処理系の
作り方がわかりました。概論的なトコだけですが。


Velocityは構文木を直接実行するタイプ(Rubyとかもそう)の言語なので、
処理系を作り込むのは比較的簡単でしたねえ。そういや。

さて、

Velocityは1.6になっていくつかのディレクティブを追加してきました。

そのうちの一つが、#defineディレクティブ。


これは、要するにevalみたいなもんです。

#set($one = 1)
#set($two = 2)

#define($result)
  #set($three = $one + $two)

  $three
#end

$result

の実行結果は

    3

です。

ではでは

この実行結果はなんだと思います?

#set($one = 1)
#set($two = 2)

#define($result)
  #set($three = $one + $two)

  $three
#end

$result

#set($one = 'ONE')
#set($two = 'TWO')

$result

まあオチが見え見えなんですけど。答えは

3

ONETWO

です。要するに#defineはダイナミックスコープになってます。


まとめると、#defineディレクティブの機能とは、
「内部に保持するブロックをキャプチャして遅延評価すること」です。
内部のブロックを評価した結果を格納するわけではありませんので、誤解なきよう。
ちなみに僕は思いっきり誤解してました...orz


Velocityのリファレンスにもそのように明記されてます


個人的には、ダイナミックスコープって、使い辛いだけだと思うんだけどなぁ。
レキシカルスコープにすればいいのに。

引数渡したいなら、もう既に#macroがあるやんけ。。。