Y's note

Web技術・プロダクトマネジメント・そして経営について

本ブログの更新を停止しており、今後は下記Noteに記載していきます。
https://note.com/yutakikuchi/

Perlの衰退議論について一言言っておくか

プログラミング言語を作る

プログラミング言語を作る

Perl衰退に関する最近の話

最近熱が上がっているPerlの衰退の話についてですが、そもそもこーゆー議論に意味ってあるんですかね?どうも信者とそうでない人の言い合いとしか周りからは見れません。僕はPerl信者でも無ければ、Perlを憎んでもいない立場の人間です。以下では個人的に気になったPerlの現状を数値で見直し、Perlを嫌う理由、Perlの使いどころというのを書きたいと思います。

Perlの現状を数値で調査した

CPANのPackage数はPypiに抜かれている

The Comprehensive Perl Archive Network - www.cpan.org はてなブックマーク - The Comprehensive Perl Archive Network - www.cpan.org
PyPI - the Python Package Index : Python Package Index はてなブックマーク - PyPI - the Python Package Index : Python Package Index
Perlをみんなが使った理由としてCPANの充実があったと思います。CPANで検索すれば何かしらライブラリが見つかり、Perlスクリプトの中でuseすれば簡単に利用できたのですごく重宝されています。少し前まではCPANの方がPypiよりもPackage数が多かったことを確認していたのですが、ここ最近では単純なPackage数の比較ではPypiが勝っています。2013/3/10現時点でのPackage登録数はCPAN27033Pypi28848です。authorの数も気になるところですが、CPANは10470、Pypiは不明でした。


Document数で他言語に劣る

Google先生にDocument数を聞いてみました。Queryが全てProgramming系の内容に一致したということが前提ですが、Document数でもPythonPHPRubyに劣っていました。(PHPさんの圧勝には笑いました。)

Lang Documents
Perl 102,000,000
Python 159,000,000
Ruby 258,000,000
PHP 19,630,000,000




Perlを嫌う理由を考えた

Perlを嫌う理由は言語としてのIFが分かりづらい点にあると思います。細かい例を挙げると沢山出てきそうなので、ここでは配列操作の例を書いておきます。

配列の存在確認や重複削除

Perlで配列から特定の値を抜き出したい時、値が含まれるかどうかの判定をする時、要素の重複を削除したい時にforeachの繰り返しを使わずに書く手段としてgrepを使います。以下それぞれのサンプルを書きますが、普通の人はgrep{ $_ eq $search } @array1やgrep { !$count{$_}++ } @arrayなどの記述を直ぐに思いつかないはずです。こういったものがperlの可読性を下げている要因の一つかと思うのですが、たった1行の追加で強力なことが出来てしまいます。

#!/usr/bin/env perl

my @array = ( 'perl', 'php', 'java', 'python' );

my $search = 'perl';
my @result = grep( /$search/, @array );
foreach( @result ) { 
    print $_ . " ";
}
perl 
#!/usr/bin/env perl

my @array1 = ( 'perl', 'php', 'java', 'python' );
my @array2 = ( 'php', 'java', 'python' );

my $search = 'perl';
if( grep{ $_ eq $search } @array1 ) { 
    print "array1 $search is Exists\n";
}

if( grep{ $_ eq $search } @array2 ) { 
    print "array2 $search is Exists\n";
}
array1 perl is Exists
#!/usr/bin/env perl

my @array = ( 'perl', 'php', 'java', 'java', 'php' );
my %count;
@array = grep { !$count{$_}++ } @array;
foreach( @array ) { 
    print $_ . " "
}
perl php java 

上の例をPythonで記述してみます。Pythonは配列に要素が含まれるかどうかをinで検知してくれます。重複削除は配列をsetに変換するというテクニックが必要なのでこれまた直感的かと言われると微妙なところですが、Perlよりは分かりやすいかと思っています。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

array = ['perl','php','java']
search = 'perl'
result = [x for x in array if x == search ]
for i in result:
   print i,
perl
#!/usr/bin/env python
# -*- coding: utf-8 -*-

array = ['perl','php','java']
search = 'perl'
if search in array:
   print search + ' is Exists' 
perl is Exists
#!/usr/bin/env python
# -*- coding: utf-8 -*-

array = ['perl','php','java','java','php']
result = sorted(set(array),key=array.index)
for i in result:
   print i,
perl php java
その他 FWが充実していない

サーバサイドをPerlで書いている人って本当に少ないと思います。僕の周りではPerlで書いているというのを聞いたこと無いです。その一つとしてWebFWの種類が少ないのとそれらが流行らなかったことが原因と考えています。僕が知っている限りだとしかCatalystとMojoliciousしか知らないんですが、Webで使えるFrameworkが他にも存在するのでしょうか?RubyRails一択じゃんと言われるとそうなんですが、PHPPythonと比較するとFrameworkの充実は劣る気がしています。
Catalyst | Perl MVC web application framework はてなブックマーク - Catalyst | Perl MVC web application framework
Mojolicious - Perl real-time web framework はてなブックマーク - Mojolicious - Perl real-time web framework

Perlの使いどころ

ワンライナーの置換はPerlの一択

ファイル内の記述を特定のルールで置換したい場合はPerlの一択だと思います。sed (コンピュータ) - Wikipedia はてなブックマーク - sed (コンピュータ) - Wikipediaなんていう置換コマンドもありますが、正規表現の使い方が微妙です。Perlコマンドの正規表現sedよりも強力にサポートされています。Perlの置換コマンドは以下のような感じで利用します。currentのディレクトリに存在するファイル全部に適用したい場合は*で、階層的に実施したい場合は*/*のように定義します。階層的な置換はfind -execを使っても出来きます。

$ perl -i.bak -pe 's/foo/bar/g' *
$ perl -i.bak -pe 's/foo/bar/g' */*
$ find . -type f -exec perl -i.bak -pe 's/foo/bar/g' {} \; 
Hadoop StreamingでPerlを使う

naoya/mapreduce-lite · GitHub はてなブックマーク - naoya/mapreduce-lite · GitHub
僕の会社ではHadoop Streamingを利用する場合はPerlを使うことがほとんどです。理由としては昔からApacheのログ解析モジュールや集計プログラムをPerlで書いていて、それをHadoop StreamingのMap/Reduceでも利用しているという流れだと思います。CPANなどのモジュールも-fileオプションやDistributedCacheを利用すればHadoop Streamingで使えます。当然柔軟なHadoop処理を書きたい場合はJavaで行うべきですが、単純な集計はScript言語で書くとなるとrubyより処理速度が速いとされるPerlで書くのが良いのでは無いでしょうか。以下はwordcountのHadoop Streamingの例です。

#!/usr/bin/env perl
# mapper.pl

use strict;
use warnings;

while( <> ) {
   chomp $_;
   my @tokens = split( /\s|\.|,|\?/, $_ );
   foreach( @tokens ) {
      $_ =~ s/(“|”|-)//g; 
      if( $_ ne "" && $_ ne " " ) {
         print $_ . "\t" . 1 . "\n";
      }
   }
#!/usr/bin/env perl
# reducer.pl

use strict;
use warnings;
my %word_hash = ();
while( <> ) {
   chomp $_;
   my @tokens = split( /\t/, $_ );
   my $word = $tokens[0];
   if( !defined( $word_hash{$word} ) ) {
      $word_hash{$word} = 0;
   }
   $word_hash{$word}++;
}

foreach my $word ( sort keys %word_hash ) {
   print $word . "\t" . $word_hash{$word} . "\n";
}
#!/bin/sh

job_name='"SocialNetwrok WordCount"'
hadoop='/usr/lib/hadoop-0.20/bin/hadoop'
streaming_jar='/usr/lib/hadoop-0.20/contrib/streaming/hadoop-streaming-0.20.2-cdh3u5.jar'
input_path='socialnetwork/input'
output_path='socialnetwork/ouput'
mapper='mapper.pl'
reducer='reducer.pl'
base_path=`pwd`
reducer_num=1

echo $hadoop fs -rmr $output_path
echo $hadoop jar $streaming_jar -D mapred.job.name=$job_name -D mapred.reduce.task=$reducer_num -input $input_path -output $output_path -mapper $mapper -reducer $reducer -file $base_path/$mapper -file $base_path/$reducer

僕は

Perlの衰退した/しない議論に興味関心は無いのですが、Perlの使いどころを理解してこれからも使い続けると思います。