2013年12月13日金曜日

【CoffeeScript】for文の戻り値メモ

CoffeeScriptの関数は明示的にreturnするべき」って言う記事が流れてきて、CoffeeScriptは触った事なかったけどちょっと気になった事があったのでメモ。

「returnを明示的にしないと元の記事だと無駄なコードが出力される」

 って、さっきの記事にはあったんだけど、Rubyとかもreturnを明示しなくても戻り値のある言語だし、わざわざreturnを明示しなくても戻り値がちゃんとあるというのにはちゃんと意味があると思ってて、できればreturnを明示しなくてもちゃんと期待通りの処理が行われる実装や設計にしていくのが好ましいようなきがした。それを意識して書いてあれば、きっと無駄なコードが出力される事もなさそうな気がする。

そこでRubyのコードとちょっと比較してみた。

 まずはCoffeeScriptのコード
(console.logの戻り値がundefinedみたいなようなのでRubyと同じような結果になるようにputsを定義しています)
01puts = (v)->
02     console.log(v)
03     return v
04  
05sample = ->
06  for i in [0,3,5]
07    puts(i + 1)
08                                                                                                                                                       
09result = sample()
10console.log(result)
結果はこうなる。
11
24
36
4[ 1, 4, 6 ]
次はRubyのコード
1def test
2    for num in [0,3,5] do
3       puts num + 1
4    end
5end
6 
7result = test
8print result
結果はこうなる。
11
24
36
4[0, 3, 5]
この二つを比べてみると、CoffeeScriptとRubyの戻り値の評価の方法が違う事がわかった。

Rubyのリファレンスを見てみると、「 for文はローカル変数のスコープに影響を及ぼさない点が 異なるからです。」ってことなので配列の定義をしている所が最後の評価として返ってきているんだと思う。

CoffeeScriptの方は、for文の中で処理された値を配列にいれて返している。何でそうなっているのかはわからないけれど、そういう評価の方法だとわかっていれば、for文でに保存してそれを配列として返すというjsの出力は無駄というわけではない。

さて、元記事にあるように return文を仕込んだ処理が以下のように書いてあったとする。
01puts = (v)->
02     console.log(v)
03     return v
04 
05sample = ->
06  for i in [0,3,5]
07    puts(i + 1)
08  return
09 
10result = sample()
11console.log(result)
そうすると以下のように処理が行われる。
11
24
36
4undefined
何かが必ず「返り値」になるっていうのは、何がどのような順番で評価されるかって言う事を意識して実装しないとってことで、それは結構プログラムを書く時に意識していた方がいい事だと思うし、戻り値が違うのはテストを書いていたりするとおかしくないのでむやみやたらにreturnで返すよりも、できるだけreturnを返さないように常に戻り値をいしきしてじっそうするほうがいいきがした。

同じような出力を期待するには下のような感じでもできるけど、結局returnは使ってない。return使わなくてもよけいなものを出力しないってことは多分できて、結局作業をする人の慣れとか、その時どんなプロジェクト上の最適化をしなくちゃいけないかって所で、バランスをとっていく所なんだと思う。なので元記事の「必ずreturn」を書くって言うのも一つの方法なんだろうと思う。

ただ、元々のJavaScriptがイケてないからこそ、「JavaScriptに変換する言語を作ろう」みたいになったはずで、そのために使っているはずなのに、出力されるJavaScriptをみてCoffeeScriptの処理の最適化の方法を考えていくのも何となく悔しい気がするのでした。
01puts = (v)->
02  console.log(v)
03  return v
04 
05sample = (list,x=0)->
06      puts(list[x])
07      sample(list,x+1) if list.length > x + 1
08 
09result = sample([0,3,5])
10puts result
書き出されたコード
01// Generated by CoffeeScript 1.6.3                                                                                                                   
02(function() {
03  var puts, result, sample;
04 
05  puts = function(v) {
06    console.log(v);
07    return v;
08  };
09 
10  sample = function(x) {
11    var list;
12    if (x == null) {
13      x = 0;
14    }
15    list = [0, 3, 5];
16    puts(list[x] + 1);
17    if (list.length > x + 1) {
18      return sample(x + 1);
19    }
20  };
21                                                                                                                                                       
22  result = sample();
23                                                                                                                                                       
24  puts(res);
25                                                                                                                                                       
26}).call(this);

0 件のコメント:

コメントを投稿