2004-11-07 (Sun)
_ モジュール関数
ゆうぞうさんとの間で認識に食い違いがあったようだ。 「モジュールの特異メソッドとしてもプライベートインスタンスメソッドとしても定義されているメソッド」という認識でよいですよね?
ゆうぞうさんは、mix-in以外でincludeを使わないらしい。 自分はどうかと言うと、置き場所が決まらない関数的なメソッドをAppName::Utilみたいなモジュールにモジュール関数として突っ込んで includeして使うことがけっこうある。
ただ、名前の衝突に弱いのがincludeの痛いところだ。 *1 C#みたいにメソッドを再定義する時はかならず、
override foo(x) ... end
とする(overrideの代りにdefで再定義しようとするとエラーか警告)、なんてのは嫌がられるだろうな。
*1 includeにかぎらずだけど。そういえば、WEBrick::CGIを継承したクラスで@configというインスタンス変数を使って失敗したこともあったりして。
_ Object#object_id
今さらながらはじめて知った。今はObject#__id__よりもこっちが推奨なのか。
もしや、Object#__send__にも代替が、と思ったけど、こっちはまだないみたい。ruby-talkで議論されていたようだ。 collect派としてはperformを推したいが、ゆうぞうさんはinvokeじゃないの?と言っていた。
-wを使わないと、Object#idのwarningが出ないのは、標準ライブラリでがんがん使われているからだろうな。
2006-11-07 (Tue)
_ モジュールによる菱形継承
[ruby-dev:29888]を見て、なるほどこういうケースだったのかと納得。
しかし、そもそもモジュールが導入された理由としてよく説明されるのは、 このような菱形継承を避けるため、というものだったりする。 が、それについては時おりモジュールでは解決されていないという反論も あったりする。
実際にモジュールでそういう継承例を見たことがなかったので興味深い (といってもメールの例を見ただけで、まだ実際のコードは読んでないけど)。 実はけっこうあるのかなあ。
2013-11-07 (Thu)
_ Array#to_procとHash#to_proc
Symbol#to_procが存在するのはもちろんのこと、ArrayやHashにto_procを定義するテクニックは便利なので、割と使われています。
[Ruby on Rails 4.0.1リリース!大量のバグ修正、3系からの移行も少し簡単になりましたより引用]
というのを見て、最近はそういう流行があるのかと思っていたら、松田さん曰く
@yukihiro_matz @shugomaeda そんなもんまったく使われてないし便利でもなんでもないと思いますよ。例によってというかなんというかfacetsにはあるみたいですが、特に便利なようには見えないですね。
[Twitter / a_matsuda: @yukihiro_matz @shugomaeda ...より引用]
とのこと。
でもそう言われるとほんとにそうなのかなと考えたくなる。
Array#to_proc
案1
まず、Adding Array#to_proc to Rubyの案。
class Array def to_proc lambda { |target| target.send(*self) } end end %w(kung ruby bar).map &[:+, "-fu"] #=> ["kung-fu", "ruby-fu", "bar-fu"]
配列の最初の要素をメソッド名として、残りの要素を引数とする案。
発想的にはSymbol#to_procの延長線上にあるものだけど、Symbol#to_procより読みにくく感じるのと、最初の要素と残りの要素の扱いがまったく異なるところが気持ち悪い。
a.map &[:+, "-fu"]
よりa.map { |i| i + "-fu" }
の方が読みやすいし、a.map {|i|i+"-fu"}
のように空白を詰めると文字数も変わらない。
案2
続いてArray#to_procの
Person.find(:all).collect {|person| [person.name, person.id]}
を
Person.find(:all).collect(&[:name,:id])
と書けるようにしようという案。
そもそもActiveRecordで全部の列をSELECTしてからcollectで間引くコードは筋が悪い。
最近のActiveRecordなら
Person.pluck(:name, :id)
でいい。
ActiveRecord以外での使い道もあまりないように思うし、map/collect以外に使えなさそうなのも減点要素。
Hash#to_proc
案1
まず、Facetsの案。
c = Class.new do attr_accessor :a end h = {:a => 1} o = c.new h.to_proc.call(o) o.a #=> 1
のようにHashの要素を与えられたオブジェクトのsetterに渡してセットするというもの。
Array#to_procの案2にちょっと似てるけど、用途が限定的過ぎてHashに持たせる機能としては適切だとは思えない。
案2
A Hash Is A Function (Hash#to_proc)の案。
class Hash def to_proc lambda {|x| self[x] } end end
のように定義して、
specialism_codes.map {|code| SPECIALISMS[code] }
を
specialism_codes.map &SPECIALISMS
と書けるようにしようというもの。
ここでfunctionと言っているのは数学的な意味での関数で、たしかに、キーの集合を定義域、値の集合を値域とするような関数とみなせるし、Hash.new {|h,k| k.to_s}
のようにデフォルト値をブロックで与えた場合はプログラミングの文脈においても関数そのもの。
Hash#callはないけど、Hash#[]を使えばProc#[]と多相的に扱えるし。
例えば
NG_WORDS = { "XXX" => true, "YYY" => true, ... }
のようなHashを用意しておくと、
clean_words = words.reject(&NG_WORDS)
や
if words.any?(&NG_WORDS) ... end
のようにmap以外の使い方もできそう。
結論
Hash#to_procの案2だったらあってもいいかなと思うが、今までほしいと思ったことがなかったので必要かと言われるとよくわからない。
他の案はArrayやHashに定義すべきものなのかというところに疑問がある(まあ、Symbol#to_procもそうだったんだけど)し、便利かどうかも疑問だったり、用途が限定されすぎている。