注意: これはネタです。
PGF の oo モジュールによる OOP では、属性(インスタンス変数)に対するクラス外のコードでのアクセスを認めていない。だから、アクセサメソッド(getter/setter)を用意する必要がある。それはいいとして、少し不便なのは、oo モジュールの設計上、メソッドは決して展開可能にならないので、「属性の値自身に展開される」ような getter が書けない。例えば次のようなコードはエラーになる。((本題とは関係のない話。PGF/TikZ にある oo モジュールの例では改行文字の無効化(行末の〈%
〉)を全くしていない。これは既定で無効化されるのだと思っていると、どうやら全くそうではなく、無効化を行わないと意図しない空白が実際に入ってしまう。この記事のコードでは \endlinechar
設定を用いた。))
\documentclass{article} \usepackage{pgf}\usepgfmodule{oo} \endlinechar=-1 % \pgfooclass{pair}{% 何の変哲もないペア(対)です \attribute first; \attribute second; \method pair(#1,#2){% コンストラクタ \pgfooset{first}{#1} \pgfooset{second}{#2} } \method form(){% 中身を出力するメソッド [\pgfoovalueof{first},\pgfoovalueof{second}] } \method get-first(){% first の getter のはず \pgfoovalueof{first} } } \endlinechar=13 % \begin{document} \pgfoonew\pairA=new pair(99,6)% インスタンスを作る \pairA.form() % 出力はできる \newcount\countA \countA=\pairA.get-first()\relax% 99 を代入したいのだがエラー! \the\countA \end{document}
従って、getter は次のように実装する必要がある。
\method let-first-to(#1){% first の値をマクロ #1 に代入する \pgfooget{first}{#1} }
これで、「値を取得する」ことができる。((ここで \pairA.let-first-to(\countA)
とするのは \def\countA{99}
の意味になるので正しくない。))
\pairA.let-first-to(\thevalue)% \countA=\thevalue\relax \the\countA %==> 99
必要な機能は実現されているが、何か気持ち悪い。
で、作ってみた。
- bxpgfooacc パッケージ (gist/zr-tex8r)
\pgfooclass
の本体中で、属性 foo を定義(\attribute foo;
)した後で
\accessor foo;
を宣言しておくと、次のアクセサメソッド(\obj
はハンドラ)が定義される。(jQuery みたいに、1 つのメソッドで引数の有無で getter/setter の区別をするようにしてみた。((そうすると、空列を設定したい場合に困る…ということは後で気付いた。非展開の \obj.foo*()
は常に setter なので空列を代入したい場合はこちらを使うとよい。あるいは \empty
を適宜使うという方法もある。)))
\obj.foo()
: 属性 foo の値(トークン列)に展開される。\obj.foo(<値>)
: 属性 foo に引数の値を完全展開したトークン列を代入する。\obj.foo*(<値>)
: 属性 foo に引数の値(展開しない)を代入する。
\documentclass{article} \usepackage{pgf}\usepgfmodule{oo} \usepackage{bxpgfooacc} \endlinechar=-1 % \pgfooclass{pair}{ \attribute first; \accessor first;% アクセサ first() を定義 \attribute second; \accessor second;% アクセサ second() を定義 \method pair(#1,#2){ \pgfooset{first}{#1} \pgfooset{second}{#2} } \method form(){ [\pgfoovalueof{first},\pgfoovalueof{second}] } } \endlinechar=13 % \begin{document} \pgfoonew\pairA=new pair(99,6)% \pairA.form() \pairA.first({\pairA.second()})% 展開して代入する \pairA.second*(\seven)% 展開せず代入する(\seven は未定義) \def\seven{7}% \pairA.form() %==> [6,7] : second は \seven でここで 7 に展開される \newcount\result % 算術演算をしてみる \result=\pairA.first()\relax \multiply\result by \pairA.second()\relax \the\result %==> 42 : 6×7 を計算した \end{document}
私の感覚では、getter がそれ自身展開可能であることは必須ではないと思う。でも、そもそも「値が取得できないもの」をフィールドとか変数とか関数の戻り値とか呼ぶのは違和感を感じる。