Perl入門ゼミ

テキスト処理、Linuxサーバー管理、Web開発ならPerl
  1. Perl
  2. 読み物

変数に型がないということの利点について考える

PHPやPerlやRubyやPythonなどのスクリプト言語に対して、変数に型がないということを否定的にとらえる人もいるかと思います。特にC言語やJavaなどの静的言語を使ってきた人にとっては、型がないということが不安材料として目に映ることが多いのではないかと思います。 

けれども、型がないということは、本当に素晴らしいことです。型がないことによって、たくさんの面倒から解放されるからです。

どのような型の値でも代入できる

まず基本的なこととして変数に型がなければどのような型の値でも代入できるということです。つまり、受け取るときに、どのような型の値を受け取るのかを意識する必要がありません。

my $str = 'Hello';
my $num = 1;
my $nums = [1, 2, 3];
my $person = {age => 2, name => 'taro'};
my $ua = LWP::UserAgent->new;

文字列であろうと、数値であろうと、配列であろうと、連想配列であろうと、オブジェクトであろうと、それを意識する必要がありません。

記述量がとても短くなる

変数の型がないことによって記述量がとても短くなります。

my $ua = LWP::UserAgent->new;

もし変数に型があれば、次のようになるでしょう(Javaの例)。

LWP::UserAgent ua = new LWP::UserAgent();

型推論で解決できるという意見があるかもしれませんが、型推論は不完全だと思います。まず右辺で型が明示されていない場合に使えないので、右辺に型がない場合は、結局型を書かないといけないからです。また型推論はソースコードのコンパイルの時間を遅くしてしまいます。ソースコードが大きくなってきた場合に、すばやく書いて、すばやく実行結果をもらうことができなくなります。また統合開発環境での、メソッドの自動補完の機能の実装が少し難しくなります。

変数に型がないと変更に強い

変数に型がないとソースコードの変更に強くなります。たとえば右辺の返す型に変更があったとしても、受け取る側のソースコードを変更する必要はありません。

# clinetはClientA型でもClientB型でもよい
my $ua = $c->client;

関数のオーバーロードが不要になる

変数の型を持つ言語は、型が異なるのだが、処理としては同一の処理を行いたい場合には、オーバーロードという機能を使う必要があります。変数の型がなければ、オーバーロードの機能は必要ではなく、ただ単にif文で分岐すればよいだけなのでとても楽です。

sub sum {
  my $value = shift;
  
  if ($valueがA型なら) {
  
  }
  elsif ($valueがB型なら) {
  
  }
}

変数に型がないことによって、関数の重複を減らすことができるという大きなメリットがあります。

複数の型を受け取りたいときに、インターフェースを実装する必要がない

Javaで大きなの労力といえば、インターフェースの仕組みを覚えて、実装することでしょう。複数の型を受け取りたい変数を作成したい場合は、まずインターフェースを実装することになります。

けれども、変数に型がなければ、インターフェースという仕組みは不要です。変数に型がないことによって、クラスの実装が重複がなくとてもシンプルになります。

C++のテンプレートのような機能も必要がない

関数の引数が配列を受け取る場合を考えてみてください。そして、配列に含まれている変数の型が、定まっていない場合を考えます。また配列自体が、普通の配列なのか、動的配列なのか、特殊なリストなのかということがわからない場合についても考えてみてください。変数に型があると、このようなたくさんのことを個別に考えて、うまくインターフェースを実装したり、C++のテンプレートのような複雑でデバッグしにくい機能を使ったりしなければなりません。

けれども、変数に型がなければ、そもそもこのような問題に直面することがありません。関数で受け取った後に、必要に応じて、if文で型を判定すればよいだけだからです。ですから、変数に型がないことによって、関数やメソッドの実装が重複なく簡単に書けます。

変数に型がないとどのような型の値が代入されているかわからないという批判に答える

変数に型がないとどのような型の値が代入されているかわからないという批判があるかと思います。可読性の問題です。でも、僕は型のない言語の可読性が低いと感じたことはないです。それは、そもそも静的言語を読むときとは、違う読み方をしているからだと思います。

スクリプト言語を読むときには、文脈を追って読むとどんな値が入っているかが、たいていはすぐにわかります。たとえば変数が次のような使われ方をしているとします。

$nums->[3];

$numsは配列(へのリファレンス)です。

$ages->{age};

$agesはハッシュ(へのリファレンス)です。

my $ua = LWP::UserAgent->new;

$uaにはLWP::UserAgent型の値が入っています。

my $c = Client->new;
my $ua = $c->ua;

$uaってなんだろう? Clientクラスのuaメソッドが何を返しているかを調べればわかるな。

こんな風に読んでいってスクリプト言語を読むことに慣れてしまえば、何の問題もないと思います。

変数に型がないことのメリットは重複を少なくソースコードがかけること

変数に型がないことのメリットは重複を少なくソースコードがかけることです。変数の型を意識しなくてもよいということは、それを利用するクラスや関数、メソッドも、利用するときに、型を意識する必要がないということです。これは重複の少ない保守性の高いプログラムを書くときにとても役に立ちます。

スクリプト言語は保守性が低いといわれますが、そもそも根拠はないと思います。静的言語はインターフェースやクラスをそのたびに実装しなければならないので、修正や変更が行いづらいです。その点では、保守性は低いといえます。

もう型のない言語は終わった、これからはハイブリッド型の言語の時代だという論評もときどき聞かれますが、その人は、型がないことのメリットを理解していないように思います。たぶんその人は、ソースコード上の見栄えという面しか理解していないんじゃないかと思います。

変数に型がないことのデメリットはないのか

あげるとすれば、パフォーマンスです。値の型が事前にわかっていれば、数値演算は圧倒的に速くなります。それが整数であることがわかっていれば、それを前提に計算ができるので、数値計算のパフォーマンスは、静的言語が圧倒的によいです。

でもパフォーマンスが問題にならない局面では、スクリプト言語を利用するのがよいと思います。

もうひとつは、メソッドや関数名の補完の実装がうまくできないので、統合開発環境には頼れないということですね。スクリプト言語を書く場合は、まるっとたくさん暗記して、統合開発環境に頼らないのが、開発効率がよいと思います。

はてなブックマークコメントへの返信

型がないことのデメリット:型があれば静的にコンピューターが発見できるバグを発見できないので人間様がやる必要がある というのはあると思う

(nkgt_chkonkさん)

これはコンパイル時に、コンパイルエラーがわかるという意味だと思います。でもスクリプト言語というのは、コンパイルと一緒に実行してしまいます。すると、バグがその時に見つかるので、バグの発見しやすさは変わらないと思います。

いくらなんでもポジティブすぎるのでは…!

(gfxさん)

ポジティブすぎる箇所を教えてください。

工エエェェ(´д`)ェェエエ工

(choplinさん)

工エエェェ(´д`)ェェエエ工となる箇所を教えてください。

一人で把握出来る規模のものを一人で作って保守していた頃は同じことを考えていた気がする

(Dolpenさん)

大規模になったとき動的言語の型がないデメリットを実感すると思う

(t2y-1979さん)

大規模になってくると、保守できなくなるという発想は、そもそも間違いだと思います。Cookpad、Github、mixi、はてな、faccbook、amazon、みんな動的な型を持つスクリプト言語を使って、大規模サイトを作っています。そう思うのは、思い込みや、プロジェクト管理の問題ではないかな。

型がない言語、書いた人間のマインドモデルに依存しすぎるので、よっぽど優れたマインドモデル持ってないと辛い

(mizchiさん)

それは静的な型がソースコードの中に見えれば、マインドモデルに依存しないといっているように聞こえます。静的な型を持つ言語で書いても、ひどいソースコードはたくさんあります。

冗長に書くことでコンパイル時にそれらの間に矛盾がないか部分的ながらチェックできるのが静的型システムの一つの利点なんです

(nakag0711さん)

なんでみんな、コンパイル時、コンパイル時って呪文のようにとなえるの? 一回プログラム実行したらわかるんじゃないのかなと思う。

実行時までエラーが判明しないというのは、アプリケーションの質を高める阻害要因になりかねないのですよ。

(mohnoさん)

プログラムを一回実行したらいいだけじゃないの。というよりも、もし統合開発環境使っているのだったら、コンパイルと実行は、同時じゃないのかなと思う。

変態整数型仕様(変数に型があるくせに代入時エラーもなく暗黙に型変換しやがる)のせいで阿鼻叫喚が絶えない,あの酷い言語に聞かせてやりたい.

どの言語のことかわからないです。

変更に強い/弱いの考え方がズレてないか?

ずれてないです。たとえば、インターフェースを作成して、実クラスにメソッドをひとつ追加しようと思うと、インターフェースにも重複して変更を加えないといけないです。動的な型を持っていれば、そこを修正する必要がないので、変更に強いんです。

PythonとRubyは同列に並べるがPHPは入れないところに謎の序列を感じた / 型推論のある言語をマジメに使ったことがあるとは思えない / 大規模になると、LLでも型を明示してIDEの補完を活用した方が断然生産性上がるよ

PHPを抜いたことには深い意図はないです。PHPはデプロイのしやすさ、Webに特化した関数がコアに初めから入っているので、利用しやすいという点ではWebプログラミングをしやすい言語だと思っています。型推論に関しては、僕の認識が甘かったです。LLでも型を明示するということの意味は、ちょっとわからないです。

爆釣ですなぁ。自分もJavaやってからRuby始めたころは、こんな感想だった。いいんじゃない、いろんな言語のよい所わかるのは。次はscalaあたりに手を付けてみると全然違う世界が広がると思う。

(kabisukeさん)

釣ってないです。普段どおり、普通に書いたら、ブックマークいっぱいついちゃっただけです。 

「一回プログラム実行したらわかる」 一度携帯電話のプログラム書いてみろ「110番に緊急呼している最中に月が変わってプリペイド契約が切れその瞬間に緊急地震速報がきた」みたいなのとかテストできんの?

(naoya2kさん)

これはもっと試験の一般的な問題だと思います。静的な型でそのプログラムを作ったから安全ということとはぜんぜん関係がないと思います。

そもそもPHPもPerlもRubyもPythonも型はあるんだけど、明示して宣言しないだけで。

(rokujyouhitomaさん)

このお話は、内部的な値の型について議論しているのではなくって、変数が型を要求しないので、どんな型を持つ値でも代入できるメリットについて書いています。

一回実行したらわかる、というのがおかしい。Perlにまともなカバレッジ分析ツールがあるのなら使ってみれば、一回では済まないことがわかるはず。

(tproさん)

一回実行したらわかるということの意味は、その部分を一回実行したら、バグが判明するという意味です。カバレッジをすべて通すという意味ではないです。カバレッジの問題は、また別問題です。分岐が正しいかというのは、そもそも静的な型付けをある言語が持っているかということとは全然別のはなしです。

これはPerlユーザーに背中から刺されるレベル

(Nkznさん)

内容がないですね。

追記

以下は勘違いしていました。

型推論で解決できるという意見があるかもしれませんが、型推論は不完全だと思います。まず右辺で型が明示されていない場合に使えないので、右辺に型がない場合は、結局型を書かないといけないからです。

型推論はもっと多くの場合うまく型を推論してくれるようです。型推論に対する利点の議論は取り下げます。

でもそんなに的外れな議論はしていないと考えていますよ。