Perl入学式の受講生だった5年前にも同じようなことを言っていたので変わってないな自分・・と思うとともに、この問題じたいがある種普遍的なのかな、という気も。
以下、掲題の件について簡単にまとめてみたいと思います。
Rubyで言うと、たとえばこんなサンプルコード。
class Foo def initialize(name:, price:) @name = name @price = price end def show return "#{@name}: #{@price}円" end end bar = Foo.new(name: "apple", price: 100) puts bar.show
結果は以下。
apple: 100円
引数としてクラスの外部から内部へ値を受け渡すためのname, priceと、クラスの内部でその値を操作するインスタンス変数のname, priceがそれぞれ別の変数であるにもかかわらず同名で記載・使用されています。
こういったことはPerlの入門者向けサンプルコードでも起こりがちで、なにしろPerlではスカラー変数でも配列変数でもハッシュ変数でも、それぞれ別の変数なのに同じ単語を使えるので、たとえばこんなことになります。
#!/usr/bin/env perl use strict; use warnings; use feature 'say'; my $apple = 100; my @apple = (101, 201); my %apple = (foo => 102, bar => 201); say $apple; say $apple[0]; say $apple{foo};
結果は以下ですが、
100
101
102
問題は、この中の
say $apple; say $apple[0]; say $apple{foo};
と並んでる3つの「$apple」は全部別物だということですね。まったく相互の関係はありません。
これ、混乱しませんか??
ぼくは初心者のときにこう思いました。「なんでわざわざ同じ名前付けるの!?」
上記の例で関係がある(同じ変数名でなければいけない)のは、以下の組み合わせです。
# 配列とその要素 @apple $apple[0];
# ハッシュとその要素 %apple $apple{foo};
同じ変数名を使うなら、こうした「同じ変数名でなければいけない組み合わせ」に限るべきで、なぜわざわざ配列とハッシュを同じ変数名にするのだ・・とただ苦しむばかりでした。
まあ実際には、ぼくもやがて初心者を卒業というか、初心者であることに飽き始めた頃、「なるほど、コードを書くときはこんな風にいろいろ揃えてしまった方がラクに感じることもあるのだな」と理解するようになりましたが、とはいえ、初心者にこれは酷だろうという気持ちには今も変わりはありません。
では、そのPerlのコード、どう直したら読みやすくなるでしょうか?
一例ですが、こんな風にすればどうかと思います。
#!/usr/bin/env perl use strict; use warnings; use feature 'say'; my $apple = 100; my @orange = (101, 201); my %lemon = (foo => 102, bar => 201); say $apple; say $orange[0]; say $lemon{foo};
これだったら、どの変数がどこに動いているのか。それぞれの代入した値がその後にどこで使われているのか、追いやすくなります。
ようは、「同じ変数名でなければいけないものだけ」を同じ変数名にするということです。
コードには色が付いていません*1。そのようなとき、色分けをする代わりに適切な変数名*2を付ける必要があるのではないか、と思うわけです。
上記を踏まえて、あらためて最初のRubyの例に戻りますが(再掲)
class Foo def initialize(name:, price:) @name = name @price = price end def show return "#{@name}: #{@price}円" end end bar = Foo.new(name: "apple", price: 100) puts bar.show
これ、たとえば以下のようにすると、どの値がどの変数を通してどこへ動いているのか、わかりやすくなると思います。
class Foo def initialize(name_arg:, price_arg:) @name_var = name_arg @price_var = price_arg end def show return "#{@name_var}: #{@price_var}円" end end bar = Foo.new(name_arg: "apple", price_arg: 100) puts bar.show
この問題、ようは読み手のトレースする力の程度に合わせる、ということなのだと思います。コードを書いているプログラマー自身は、どの変数がどの値を抱えているのか、頭の中ですでに追えている状態なので、変数名によって値の経路を示す必要はもうなくて、むしろ別の理由、たとえば異なる中身を持った変数同士が同種の属性や役割を背負っていることを示すために、同じ変数名を付けてカテゴライズしておきたい、みたいな考えがあるのかもしれません。
しかし入門段階の人は、普通はそういったトレースをする力が十分にはないがゆえに、変数の名前からその中身の値を想像しようとしますから、異なる値・異なる変数であるにもかかわらず同じ名前がついていると、混乱が生じやすいということではないかなと。
このあたりの問題を認識した上で、その状況に応じてどうするべきなのか(異なる中身を持つ変数同士に同じ名前を付けるのか、それをしないのか)を考えられると、より良いかたちで書き手と読み手のコミュニケーションが成立しやすくなるのではないか、と思っています。