From: Yukihiro Matsumoto Date: 2014-07-13T00:23:57+09:00 Subject: [ruby-list:49875] Re: Rubyへの要望(願望) まつもと ゆきひろです In message "Re: [ruby-list:49872] Re: Rubyへの要望(願望)" on Sat, 12 Jul 2014 21:22:58 +0900, MASAKI Yuhsuke writes: |whileを使うことはほとんどないのですが、可能であればむしろブロックにcontinue節が欲しいくらいです。 |something do | # main |continue | # continue |end 思いつきで言うのは簡単ですが、実際に採用するためには、これに どういう意味を与えるかはきちんと定義する必要があります。たと えば、これで作られたsomethingメソッドがブロックをどう呼び出す と#continueが実行されるのか(あるいは実行されないのか)、そのた めには言語のどの部分がどういうふうに情報を保持し、どういう条 件で実行するのか決めなければなりません。以前にも(その時は else節でしたが)考えてみましたが、どうにも良いセマンティクスを 思いつきませんでした。 |さらにいえばこれをやるならば、ブロックにrescueやensureやelseをつけられるようにしてほしいとも思います。 rescueやensureは簡単ですが、明示的にbeginでくくるのと大差な いと思います。また、ブレースで作るブロックにはrescueやensure は似合わないようにも思います。elseはcontinue同様、セマンティ クスの定義が困難ですね。 |> |#文字列の強制エンコーディング処理 |> そういうのがあるといいですね。もうちょっと具体化するといいの |> ですが。 |> |lvって割と自動認識してくれるよなー、と思ったのですが、lvはアジア言語に特化しているのですね。 |geditの言語認識は予め候補となるエンコーディングを候補順に並べておく必要がありますが、だいたい認識してくれます。ここらへんが妥当な線かな、とは思います。 |Teaも同じように対象となるエンコーディングを指定しておくことで自動認識してくれます。恐らくはまた違ったメカニズムだとは思いますが、これもひとつでしょうか。 |それぞれの実装について具体的に述べることは(知識不足で)できませんが、 |完全な自動化を目指すなら、各エンコーディングの特徴となる部分、 |例えば先頭のBOMや、UTF-8の可変長認識のためのバイトルール、エスケープシーケンスなどから「そのエンコーディングの特徴を満たしているか?」を判定、 |使用するエンコーディングの優先度をStringのクラス変数に持たせておき、ISO8859のようにそのエンコーディングのバイトルールが競合するものについてはその優先度に基づいて決定。 |(より完璧に近づけるならば、単語などでそのエンコーディングに頻出するパターンを照合することで確率の高いエンコーディングをもとめ、 | それとは別にユーザー定義の優先順位を決めるクラス変数を持たせておき、そこで指定されていれば推測された「確率の高いエンコーディング」に代えて | 同様のバイトルールを持つユーザー指定のエンコーディングであると仮定する、というのはどうでしょう) | |優先度のアクセサは |String.encoding_priority |String.encoding_priority= |とか。そして、その機能がつけばguessを入れ替えるか、もしくは |String#full_guess |とか。さらには#force_encodeを使いたいのですが、これも名前問題がありそうなので、 |String#auto_convert(encode) |でしょうか。 中田さんもおっしゃってましたが、まずはgemで実現すべきでしょ うね。なんでもコアに含めるのが良いとは思えません。 |> |#Zsh EXTENDED_GLOBのサポート | |> ZshのGlob全部はシェルでないRubyでは実現できなかったような記憶 |> があります。どこまで欲しいのか、もうちょっと具体的な提案があ |> ると採用しやすいかもしれません。 |> |Zsh manualにあるGlob Operator: | <[x]-[y]> 数値ベースのglob | (...) グループ化 | x|y OR | ^x 否定 | x# 1回以上のx | x## 2回以上のx | |と、Glob Qualifierですね。 |特に便利なケースとしては、 | **/<->(/n^D) →カレントディレクトリ以下(再帰)の数値の非ドットディレクトリを数値順ソートで |のようなものです。 シェルでないRubyでここまで必要なことってありますかね。少なく とも私はzshでさえもこれらのパターンを使ったことはありませんし、 Rubyでほしいなと思ったこともありません(globのあとにフィルター やソートをすればいいし)。まあ、誰かが「私が実装する」と手をあ げたらその時はじめて検討するレベルですね。 |> |#File#flockにブロックを |> flockはfileがcloseすると解放されるので、 |> |> File.open(path, "r") do |f| |> f.flock(File::LOCK_EX) |> # ... |> end |> |> で十分だと思うのですが。ブロック形式の方が便利なケースを思い |> つきませんが、もしあるということでしたら再提案してください。 |> |r+で開いて内容を確認し、内容によって書き込むようなケースですね。例えば |File.open(path, "r+") do |f| | f.flock(File::LOCK_SH) | obj = Marshal.load(f) | f.flock(File::LOCK_UN) | f.seek(0) | #... | if cond | f.flock(File::LOCK_EX) | Marshal.dump(obj, f) | f.flock(File::LOCK_UN) | end |end | |また、このようなことをしないなら、そもそもfileをopenする時点でロックを獲得するような呼び方ができるといいというのもあります。 うーん、すでに述べたように明示的なunlockはほぼ不要ですから、 File.open(path, "r+") do |f| f.flock(File::LOCK_SH) obj = Marshal.load(f) f.seek(0) #... if cond f.flock(File::LOCK_EX) Marshal.dump(obj, f) end end で十分ではないでしょうか? しかも、ブロックでくくることで一度 unlockしちゃうとそこでロックのない瞬間が発生するのでレースコ ンディションが起きそうな気がします。 |> |#メソッド名にsymbolを増強 | |実際に遭遇したケースとしては、文字列のエスケープ処理と、文字列のエスケープ処理通過指示(verb)で、 |通常のメソッドの形でなくsymbolを使うことでスッキリみせたい、というのがありました。 |つまり、 |^ "Hello" |のように書きたかったのですが、^インスタンスメソッドを定義した上でinstance_evalを呼んでもself.^を読んでくれないため、そうなりません。 |記号が残っていない、というのは感じますが、DSLではもうちょっと書き方に自由度が欲しいな、と思うことがちょくちょくあります。 |Ruby組み込みでない(DSL処理スクリプトが処理前に展開する)マクロを書いてしまえばいいのかな、 |とは思いますけれど、それもなんだか嬉しくない気がして。 DSLとして文法を使い倒したい派からは「マクロ欲しい」とか、「メ ソッドとして使える記号を増やしてほしい」という要望を以前にも 頂いたことがあります。が、Rubyとしての読みやすさを阻害する気 がして積極的になれません。通常のメソッドの形も悪くないですよ。 |> |# Kernel.syscallにStringを渡せるようにしてほしい |> 「まんま」といわれてもちょっとわからないのですが、syscallでシ |> ステムコールの指定を番号ではなく文字列で指定したいということ |> でしょうか。 |> |これも、mkfifoを楽にするために欲しいな、と思ったことですね。おっしゃるとおり、システムコール名で指定したいのです。 |他のプラットフォームについて充分に調べられなかったため、syscallを数値で指定すると移植性に影響がでそうだ、と思いまして。 これも中田さんから指摘がありましたが、mkfifo gemをどうぞ。 ご要望もそちらへ。 |> |# next/redo/breakのターゲットを明示できるようにする |次のようなケースです。 | |catch :nested do | a.each do |i1| | begin | b.each do |i2| | case | when i1.nil? | throw :nested | when i2 < 10 | next | else | raise | end | end | rescue | redo | end | end |end | |breakの代わりにthrow, redoの代わりにraiseを使っています。 |このbreakとredoはa.eachに対して行いたい、ということです。 |このようなケースで、どこかに処理をいれようとすると同じ処理を複数箇所に書くことになるんだよな、 |と思って古いコードを探したのですが、発見できませんでした。ごめんなさい。 なにを問題にしてらっしゃるのかわかりませんでした。適切な例題 が見つかりましたらまたどうぞ。 |> |# サブプロセスからの読み戻し |> aliasを使ってはどうでしょうか? 適切な名前があれば別名をあら |> かじめ用意するのもよいのかもしれません。 |> |Kernel.`って文字列しかとりませんよね?argをArrayで渡したいということなのですが… |名称は、ベタにKernel.cmdか、あるいは分かりにくいですけど、Kernel.csubとか? |後半のは、こういうことですね。 |str = nil |IO.popen(cmd, "w+") do |io| | io.write(input) | io.write_close | str = io.read |end これもpopenなどを活用してgemを作る(あるいはすでにあるかも)の がよろしいのではないかと思います。 |> |# 先進的演算子 | |> |.= |> こういうのが欲しいのはわかりますが、この記法はあまりよくない |> ように思います。 |> |では、パーサが大変になりそうですが、 |obj ->method(arg) |かぶりをさけるなら |obj <-method(arg) |のほうがマシでしょうか。 どちらも既存の文法と衝突します。文法デザインは難しいですね。 |> |# 軽量な起動, precompile |> Emacsでもそうですが、最近マシンが高速化していてそういう対処 |> は不要になってきているようです。起動時間のかかるJRubyならと |> もかく、CRubyでそこまで必要なケースはかなり少なくなっている |> とおもうのですが、なにか事情があるのでしょうか。 |手元で起こっているケースとしては、シェルスクリプトで一部処理でRubyを使うものにしています。 |シェルスクリプトの1回のループで行われるRubyスクリプトの実行は5回です。 |大体1回で3万ファイル程度を対象にするため、15万回Rubyを起動し、スクリプトをコンパイルすることになります。 |この場合スクリプトが非常に小さいため、ほとんどはforkのコストですが、なんだか同じ内容をコンパイルばっかりして無駄な気がします。 これだけ実装が大変そうな機能を「無駄な気がします」で提案され ると、実装者が涙します。15万回だろうと100万回だろうとCPUは文 句を言いませんし、賭けてもいいですが実装してもほとんどの人は この機能を使わないし、感謝もしないと思います。 ただ、RubyMotionのようなAOT(Ahead Of Time)コンパイル処理系で あれば、それはそれで価値を感じる人も少しはいるとは思います。 |#Object.remove_module |prependがあるのならば、モジュールを外すことができれば、一時的にメソッドを書き換えるようなことは |スマートかつ容易に行えるように思えます。 メソッドキャッシュや将来のJITコンパイルの効率化なども考えると 動的にクラスの機能が変化するのはあまりお勧めできません。でき れば避けたい。 まつもと ゆきひろ /:|)