2007年02月19日 04:00 [Edit]

ruby - var := 1 って my $var = 1; のこと?

タイトルどおりだとしたら、高橋さんに一票。

Matzにっき(2007-02-05)
高橋(Maki)さんによる:=オペレータへの反対意見。
思っているよりもずっとずっと人生は短い。
「:=」をどういうときに使えばいいか説明するのが難しそう(特に初心者に)

スラッシュドット ジャパン | まつもとゆきひろ 答える
また、Rubyのローカル変数のスコープの点に気がついた彼[引用者註:Larry Wall]はやっぱりとても鋭い人だと思います

私にとっても、Rubyのスコープルールは一番違和感があるところでして。

例えば、以下のコードは、

foo = 1
loop do
   puts foo
   foo = 2
   puts foo
   break
end
puts foo

1,2,2と出力しますが、以下のPerl Codeは1,2,1です。

$\="\n"; # so print does puts
our $foo = 1;
{
    print $foo;
    my $foo = 2;
    print $foo;
}
print $foo;

JavaScriptはまた特殊でして、var宣言された変数はlexical scopeの内側からは見えません。

// double-click to execute
var foo = 1;
(function(){
   alert(foo); // undefined
   var foo = 2;
   alert(foo); // 2
})();
alert(foo);    // 1

よって厳密にはfunction localといいます。

話をRubyに戻します。それだけならまだいいのですが、Perlで$scalar,@array,%hash,&subroutine,*typeglobと型の違いを示すのに使っている記号(Perl語でsigil)が、local,$global,@instance,@classとスコープの違いに使われているところも面食らうところです。もっともPerl 6では、twigilといって、$*ARGS, &?BLOCK, という具合に、二番目の記号で特殊変数を区別するようになっているのでちょっとRuby的になっていますが、それでも$.instanceのように、用途が直感的にわかる記号の選び方をしています。まあ後だしじゃんけんゆえ当然なのですが。

で、:=です。Matz案では

foo = 1
loop do
   puts foo
   foo := 2
   puts foo
   break
end
puts foo

とすると1,2,1と出力される、すなわち:=で代入した変数は、Perlのmy変数と同じ扱いになる、ということを想定しているのでしょうか?会話の流れからするとどうもそのようなのですが。以下、そうだとして話を進めます。

これ、混迷をさらに深める事になると思います。スコープを記号で切り替えるのでもすでに違和感大きいのに、今度は演算子となると...PerlからmyをパクるなりJavaScriptからvarをパクるなりした方が RSL (Ruby as Second Language) のユーザーにやさしいと思います。

さらに、Perl 6で:=がbinding operatorとして使われていることもあります。要は変数の別名を作る演算子で、例えば以下のコードは1,2と出力します。

my $a = 1;
my $b := $a;
say $b;
$a = 2;
say $b;

まあそれを言ったらPascalでは:=が代入ですし、別の言語だし演算子に別の意味があってもいいですし、グラスの底に顔があったって芸術は爆発しているからいいのですが(なんのこっちゃ)、the principle of least surpriseから行くと、too surprisingなのではないでしょうか。

....待てよ、

|foo| = 1

というのはいかがでしょう?これだと絶対確実にblock localなiterator variableとの整合性も取れますし。foo := 1よりはRubyishに見えます。|foo|というのは一番rubyらしいconstructですし。キーストロークが増えるという意見もありますが、

|foo, bar, baz| = 1, 2, 3

とやればそれも気にならないでしょう。

Dan the Broken Ruby Speaker


この記事へのトラックバックURL

この記事へのトラックバック
弾さんによる「:=」へのツッコミ。 Rubyのsigilは(Perlと違って)スコープを表すのに面食らう Perl出身の弾さんゆえ、Perlに親しんでおられるのはわかるが、 近代的言語においてsigilを採用するのであれば、 その示すべきものは絶対にデータタイプではない。 データタイ...
404 Blog Not Found:ruby - var := 1 って my $var = 1; のこと? 【Matzにっき】at 2007年02月25日 02:10
この記事へのコメント
Rなんかは、
foo <- 1
local({
cat(foo,"\n")
foo <- 2
cat(foo,"\n")
})
cat(foo,"\n")
なら 121

foo <-1
repeat{
cat(foo,"\n")
foo <- 2
cat(foo,"\n")
break
}
cat(foo,"\n")
なら 122

localやfunctionは無名環境を作ります
ブロック内のスコープは貴方次第。

昔のインタプリタの名残?で":="の残骸があって、

":=" <- function (x, value)
{
assign(deparse(substitute(x)), value, envir = parent.env(environment()))
}
hoge := runif(100) * 1000

も出来るとか。

任意の演算子を作る場合は %で挟んで
> "%(^_^)%"<-function(x,value){x+value}
> 1 %(^_^)% 2
[1] 3
等と何でもあり...
Posted by R at 2007年03月02日 23:23
Perlという極めて特殊な言語を中心に語られても...
Posted by M at 2007年02月25日 11:06
Pascal信奉者として:=を特殊な意味に使うのは許せん。
代入をぜんぶ:=にしなさい。
Posted by Bar at 2007年02月25日 08:49
> JavaScriptはまた特殊でして、var宣言された変数はlexical scopeの内側からは見えません。

見えますよぉ。
var foo = 1;
(function() { alert(foo); // 1 })();
例に出されたものは
(function(){
 var foo;
 alert(foo);
 var foo = 2;
 alert(foo);
}();
と解釈されます。
参照: http://d.hatena.ne.jp/m-hiyama/20051209/1134086113
Posted by mal at 2007年02月23日 21:31
「Rubyに{}は有るから済まないでしょ」
Posted by   at 2007年02月22日 05:20
PHPのブロックはスコープが無いので1,2,2ですが、JavaやC/C++のブロックはスコープがあるので1,2,1です。

他の言語もブロックレベルのスコープを持つ言語なら、普通に1,2,1と表示されるはずです。

と言う訳でPHPとRubyが異端!?

個人的にはスクリプト系言語にブロックレベルのスコープは無くても良いような気がしますが、Java/C系に慣れているプログラマにはブロックでもスコープほしいと思うのかな? 「Rubyには{}が無いからいいでしょ」で済まない?
Posted by yohgaki at 2007年02月21日 15:38
Rubyのような挙動(1,2,2)が一般的だとばかり思ってました。
JavaやPHPだってそうですよね?
Posted by abc at 2007年02月20日 13:19
perlユーザの視点からrubyのsyntaxにケチつけるのは不毛だと思うのですが。
それこそPascalユーザがC言語の代入が「=」なのは違和感がある、ユーザに優しくない、と言うようなもんです。
rubyを使うのはruby脳にコンテキストスイッチしたユーザであって、ruby脳にコンテキストスイッチしないperl脳のままのperlユーザではないでしょう。
Posted by at 2007年02月19日 14:30
prefixでスコープを表すことの違和感ってPerlユーザだけでしょ。
Perlをスキップするプログラマーも増えている今では問題なし。

記号だらけのPerl6に違和感を感じる人の方がはるかに多いと思うよ。
いつ出るのか知らないけど。最初は5年前に出るって話だったよね…
Posted by nanashi at 2007年02月19日 12:00