代入の返り値は代入値
2010-02-09 23:27:42
例えば memoize しながらフィボナッチ数列を求める場合。
class Fibonacci def initialize @memo = [0, 1] end def fibonacci(n) @memo[n] || @memo[n] = fibonacci(n - 2) + fibonacci(n - 1) @memo[n] # この行は省略しても結果は同じ end end fib = Fibonacci.new 10000.times { |n| fib.fibonacci(n) }
これで何が嬉しいのかというと、プロファイリングしてみるとこんな結果が現れます。
fibonacci メソッドの最後の行を省略しなかった場合
$ time ruby -rprofile fibonacci.rb % cumulative self self total time seconds seconds calls ms/call ms/call name 67.92 3.24 3.24 29996 0.11 0.21 Fibonacci#fibonacci 16.98 4.05 0.81 59992 0.01 0.01 Array#[] 6.29 4.35 0.30 1 300.00 4770.00 Integer#times 3.56 4.52 0.17 19996 0.01 0.01 Fixnum#- 2.73 4.65 0.13 9954 0.01 0.01 Bignum#+ 2.52 4.77 0.12 9998 0.01 0.01 Array#[]= 0.00 4.77 0.00 2 0.00 0.00 Module#method_added 0.00 4.77 0.00 1 0.00 0.00 Fibonacci#initialize 0.00 4.77 0.00 45 0.00 0.00 Fixnum#+ 0.00 4.77 0.00 1 0.00 0.00 Bignum#coerce 0.00 4.77 0.00 1 0.00 0.00 Class#inherited 0.00 4.77 0.00 1 0.00 0.00 Class#new 0.00 4.77 0.00 1 0.00 4770.00 #toplevel real 0m6.005s user 0m4.776s sys 0m1.184s
fibonacci メソッドの最後の行を省略した場合
$ time ruby -rprofile fibonacci_fast.rb % cumulative self self total time seconds seconds calls ms/call ms/call name 66.39 2.39 2.39 29996 0.08 0.14 Fibonacci#fibonacci 8.06 2.68 0.29 29996 0.01 0.01 Array#[] 8.06 2.97 0.29 19996 0.01 0.01 Fixnum#- 6.94 3.22 0.25 1 250.00 3600.00 Integer#times 5.56 3.42 0.20 9998 0.02 0.02 Array#[]= 5.00 3.60 0.18 9954 0.02 0.02 Bignum#+ 0.00 3.60 0.00 1 0.00 0.00 Fibonacci#initialize 0.00 3.60 0.00 1 0.00 0.00 Class#inherited 0.00 3.60 0.00 2 0.00 0.00 Module#method_added 0.00 3.60 0.00 1 0.00 0.00 Class#new 0.00 3.60 0.00 45 0.00 0.00 Fixnum#+ 0.00 3.60 0.00 1 0.00 0.00 Bignum#coerce 0.00 3.60 0.00 1 0.00 3600.00 #toplevel real 0m4.516s user 0m3.600s sys 0m0.904s
実行時間が約 25% 短縮されました。
注目するポイントは 2 行目の Array#[] メソッド、つまり配列から値を引き出す処理の回数が半分になっているというところ。どうしてこうなるかは、コードの意味を考えながら読めばすぐにわかると思います。ただ、こういう最適化によって、有意な効果を得られるケースがあるのかは疑問ですが・・・。
でもせっかくなので、代入の返り値はどうなってるのか、言語ごとに調べてみました。
Ruby
p (foo = "bar") # => "bar"
JavaScript (Rhino)
var foo; print(foo = "bar"); // => bar
Perl
my $foo; print $foo = "bar"; # => bar
PHP
var_dump($foo = "bar"); // => string(3) "bar"
MySQL (これはちょっと番外編?)
mysql> SELECT @today := CURDATE(); +---------------------+ | @today := CURDATE() | +---------------------+ | 2010-02-09 | +---------------------+ 1 row in set (0.00 sec)
と、ここまでは、どれも代入値が返ってくるようですが・・・
Python
print(foo = "bar") # => SyntaxError: invalid syntax
Python では Syntax Error となります。
これを知って何の役に立つのかイマイチわかりませんが、こういうことになっていますよ、ということで。