JavaScript ではよくある、こういう書き方。

一応説明すると、これは実行時に外側の無名関数を実行します。外側の無名関数は返り値として、内側の無名関数を返し、変数 counter には内側の無名関数が代入されます。

これの何が嬉しいのか。

  • counter 関数が内部に持っている変数 i は隠蔽されており、外から変更できない。
  • グローバル空間の汚染は counter 1 つだけ。

といったところでしょうか。とにかく、 JavaScript 脳の人はこういう感じのコードをよく書いている気がします。 JavaScript にはオブジェクト指向によくある protected や private といったアクセスレベルを制御する機能が無いため、これの応用で内部の変数やメソッドを隠蔽することが多いです。 Prototype や jQuery でもそういった使い方がされています。

このように、 JavaScript では無名関数の中にスコープを閉じ込めることができ、これをクロージャと呼びます。

で、最近久しぶりに勉強している Perl 。 Plack のコードを読んでいる中で、 Perl にも無名関数とクロージャがあるということを知ったので、試してみました。

上部のおまじない的なものを除けば、やってることは本質的に何も変わりません。

ついでに Ruby も。これもやっていることは特に変わらないと思います。

Python にも無名関数 (ラムダ) はあるので、同じようなことができそうな気がしたのですが、うまくいかず、代わりにこんな書き方に。

これはクロージャではなく、ジェネレータという機能を使っています。内部の変数が隠蔽されており、名前空間の汚染も 1 つだけですが、最初は関数だった counter にジェネレータをぶち込むというのは、お行儀的にはよくないかもしれません。

で、 PHP でも 5.3 からは無名関数・クロージャが使えるようになったので、試してみたのですが、以下の JavaScript 的な記述では parse error となりました …

以下のように書き換えると動きますが、これでは名前空間の汚染が 2 つです。

そして、何かもう方向を見失っている例。

変数の名前空間汚染は 1 つだけど、クラス名の名前空間まで汚染してしまっている上、返り値が文字列になっています。 (__toString はそのように定義しないといけないため)

そして、一応数値を返すようにしたものが以下。

なんか、 JavaScript と Perl の話だったはずが、暗に PHP を Dis る結果になってしまったので、今日はこの辺で。

, , , , , ,

ささたつ (@sasata299) さん「Rubyのスコープややこしや〜 」を読んで、ちょっと驚きだったので、調べてみました。

検証用コード

ささたつさんのコードとはちょっと違いますが、調べようとしていることは特に変わりません。

Ruby 1.8.7

apt-get でインストールした MRI の場合。

$ ruby -v
ruby 1.8.7 (2010-01-10 patchlevel 249) [i486-linux]
$ ruby check_scope.rb
r = 15
n = 10

?!

これはつまり、はじめに定義した変数 n が、イテレータにより上書かれていることを意味します。

JRuby 1.5.1

ソースコードから手動インストールした JRuby。

$ jruby -v
jruby 1.5.1 (ruby 1.8.7 patchlevel 249) (2010-06-06 f3a3480) (OpenJDK Client VM 1.6.0_18) [i386-java]
$ jruby check_scope.rb
r = 15
n = 10

1.8.7 と全く同様の結果に。Ruby 1.8.7 を実装したものなので、当然といえば当然ですね。

Ruby 1.9.2

先日リリースされたばかりの最新版。ソースコードから手動インストールしました。

$ ruby192 -v
ruby 1.9.2p0 (2010-08-18 revision 29036) [i686-linux]
$ ruby192 check_scope.rb
r = 15
n = 100

こちらでは、イテレータ内での変数 n はローカルに閉じており、はじめに代入した n は上書かれていないことがわかります。

1.9.2 の動作が、一般的に見て自然と思われるものではないでしょうか。これ、いつのタイミングで変わったんですかね ?

昨日の記事『Ubuntu 10.04 で JRuby on Rails on GAE を始めるまでの作業ログ』では、Rails 2.3.5 で GAE プロジェクトを作りましたが、Rails 2.3.8 でも作れるようになっていました !

で、書かれていた通りやってみたところ、あっさり動きました。

作業上の変更点は以下のような感じだとおもいます。

  • Gemfile を手書きで書き足さなくてよくなった
  • ails238_appengine.rb に tiny_ds オプションはあるものの、動かない ?

というわけで、昨日書いた記事は、書いた時点で既に陳腐化してということですね …

, , ,