2010-06-16
Ruby で変数宣言がほしい、とな?
ruby | |
Thor タスクを書いていて
desc "load KVS_FILE", "load data from given KVS file" def load(kvs_file) case kvs_file when "shift" ksv_file = Dir.glob("kvs/requests/*").sort.first when "pop" ksv_file = Dir.glob("kvs/requests/*").sort.last end p kvs_fileload("shift") しても "shift" が表示されちゃう謎の現象に遭遇。
とか色々調べること10分。原因に気付いて愕然としました。てことで、やはり Ruby にも変数宣言が欲しい、というか、無いとダメだ!しかもオプションで使えるレベルでなくデフォ強制が必須。ワンライナー(golf)用途に、disableにするオプションがあるぐらいの勢いで。
no title
あるあるーw でもJavaScriptみたいな仕様ならいらね。
人間の単純なミスだからそれは使う側のユーザの問題
という正論が成立しそうだが、それは違う。そういうつまらないミスを言語(環境)が指摘してくれることで、ユーザはもっと本質的なロジック部分だけに集中できるのだ。というのも、コンパイラ言語を使った後でRubyに戻ってくると、そういう非本質的な部分(変数名を必死にケアするとか)にも神経を使う必要があって、同じ時間のコーディングでも遥かに疲れるのだ。
強く同意する。
よくアジャイル開発を信奉する人が、「テストをすれば大丈夫、コンパイラのエラーチェックなんていらね」みたいなことを言うけど、テストの実行はけっこうな時間がかかるんだから、テストを実行しないと見つけられないよりも、テストをしなくても見つけられるほうが、ずっとアジャイルじゃね?
Rubyでいまから変数宣言を導入するのは難しいだろうけど、今回の場合なら、代入はされたけど他の箇所で使われていないようなローカル変数を検出する機能がRubyにあればいいんじゃないかな。
あとは、代入されてないのに参照されているローカル変数 (たいがいtypo) の検出ができれば最高だけど、Rubyではレシーバなし引数なしのメソッド呼び出しと、ローカル変数との区別がつかないから、難しいなあ。個人的には前者を禁止したいんだけど。
# Ruby にも pycheker みたいなのがほしいね。
- 37 http://reader.livedoor.com/reader/
- 31 http://egone.org/
- 20 http://www.google.co.jp/reader/view/
- 17 http://d.hatena.ne.jp/
- 14 http://www.rubyist.net/~kazu/samidare/
- 12 http://www.google.com/reader/view/
- 9 http://pipes.yahoo.com/pipes/pipe.info?_id=04913f684f1141e0b48179f97811ce12
- 8 http://momegoto.g.hatena.ne.jp/
- 8 http://www.google.co.jp/reader/view/?hl=ja&tab=wy
- 8 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=org.mozilla:ja:official&channel=s&q=php+連想配列+ソート&lr=&aq=f&aqi=g1&aql=&oq=&gs_rfai=
p defined?(a) # => nil
a = 1 if false
p defined? a # => "local-variable"
ここでの問題の本質は、未使用変数の検出だと思います。
レシーバなし引数なしのメソッド呼び出しは左辺値式には現れないので、ローカル変数との区別は着くと思います。
ruby2rubyを使えば構文木が得られるので、ブロック内の個々の変数の宣言参照バランスを調べることで未使用変数は判ると思います。
flayに組み込めそうですね。
それが静的に可能かどうかが問題です。defined? でわかっても、今回の場合ではうれしくありません。
> ここでの問題の本質は、未使用変数の検出だと思います。
代入したけど未使用なローカル変数と、代入してないのに参照しようとしているローカル変数ですね。
> レシーバなし引数なしのメソッド呼び出しは左辺値式には現れないので、ローカル変数との区別は着くと思います。
こちらの説明が足りてませんでした。正しくは、「レシーバなし引数なしのメソッド呼び出しと、*代入してない*ローカル変数との区別がつかない」です。
> ruby2rubyを使えば構文木が得られるので、ブロック内の個々の変数の宣言参照バランスを調べることで未使用変数は判ると思います。
> flayに組み込めそうですね。
期待してます。
動的・静的って表現は難しいですね
・変数の(示すインスタンスの)型は動的に決まる
・ローカル変数のスコープは静的に決まる
・ローカル変数のスコープは実行/否に関わらず、代入から始まる
という意味です
あと、ruby で「*代入してない*ローカル変数」は出来ないと思うのですが?
ブロックの最後の式の値がブロックの値になる事でしょうか?
> ・ローカル変数のスコープは静的に決まる
> ・ローカル変数のスコープは実行/否に関わらず、代入から始まる
おーこれはわかりやすい。参考になる情報をありがとうございます。
> あと、ruby で「*代入してない*ローカル変数」は出来ないと思うのですが?
言語仕様上はそうですが、「ローカル変数に関するバグを検出する」という観点からは、以下のような場合が考えられます (本文でもちょっと触れてます)。
name, password = 'kwatch', 'anpontan'
p pass # 「pass」というローカル変数を使ったつもりが実は代入してなかった
p namae # 「name」というローカル変数を使ったつもりが実は typo してしまった
どちらの場合も、代入されてないのでローカル変数ではありません (これはef3さんのおっしゃる通りです)。ただ、ユーザはどちらもローカル変数のつもりで書いているので、これらをうまく検出しないと「ローカル変数に関するバグを静的に検出する」ことにはならないと思います。そして、こういったのが「レシーバなし引数なしメソッド呼び出し」と見分けがつかないよね、という意味でした。ちょっと説明がわかりにくかったですよね。すいません。
#スクリプト言語にそんなこと求める方が間違いだ!
#という意見もあるかと思いますが、今は単に思考実験
#だと思ってください。
ローカル変数に限らず、typo の発見はかなりハードルの高いテーマですね。
スクリプト言語処理系の外部で(lintの様に)解析する方法も含めて、プログラマのミスを適切に指摘する機能は、重要な機能だと思います。