あなたが次に学ぶべきプログラミング言語を選ぶための重要な基準
「複数のプログラミング言語を使えるようになりたいけど、何を選んだらいいか分からない…」
プログラミング言語はたくさんの種類があり、特性も様々です。
自分が次にどの言語を学べばいいのか決められず迷ってしまいますよね。
そんな時は判断基準を設ければいいのです。
代表的な判断基準を紹介します。
似た言語を学んでも意味がない
似た言語とは次のようなものです。
- 作れるソフトウェアが同じ
- パラダイムが同じ
例えば、Rubyを使える人がPerl, PHP, Pythonなどの言語を学んでも、得られるものは少ないと思われます。
なぜならば、これらの言語で作れるソフトウェアの種類が変わらないからです。
これらの言語で作れる主なソフトウェアは
- Webサーバサイドのプログラム
- コンソールアプリケーション(画面のないアプリケーション)
です。同じタイプのソフトウェアしか作れないのであれば、新たに学ぶ必然性は生まれません。
また、これらの言語はすべて同じパラダイムの言語です。Perl, PHP, Python, Rubyはいずれも
- クラスベースオブジェクト指向言語
- 動的型言語
- LL言語 = スクリプト言語 = インタープリタ言語
- 命令型言語
です。
パラダイムの同じ言語は基本的な考え方が同じなので、複数の同パラダイム言語を学んでも、学べることは本質的に同じです。
なので、「違うタイプの言語を選ぶ」という基準が有効なんです。
違うタイプの言語を学ぼう
作れるソフトウェアが違う言語を選べ
先ほどの4つの言語(Perl, PHP, Python, Ruby)のどれかを使える人ならば、Webサーバサイドのプログラム、コンソールアプリケーション以外のソフトウェアを作れる言語を選ぶと良いんです。
例えば、Javaを学べばAndroidアプリを作れるようになります。Swiftを学べばiOSアプリを作れるようになります。
パラダイムが違う言語を選ぼう!
動的型言語と静的型言語
- 動的型言語 = PHP, Python, Ruby, Perl, JavaScript, Lua等
- 静的型言語 = C/C++, Java, Objective-C, Swift, C#, Visual Basic.NET, Go, Scala, Kotlin等
動的型言語の例(JavaScript)
var str1 = "Hello"; var num1 = 10;
変数に型がなく、すべてvarで変数を宣言しています。
静的型言語の例(C#)
string str1 = "Hello"; int num1 = 10;
変数に型があり、string, intなど型を指定して変数を宣言しています。
手続き型とオブジェクト指向
- 手続き型言語 = C言語, Fortran, COBOL, Pascal等
- オブジェクト指向言語 = クラスベースとプロトタイプベースの2種類ある
- クラスベースオブジェクト指向言語 = C++, Java, PHP, Ruby, Python, Swift, C#, VB.NET, Kotlin等
- プロトタイプベースオブジェクト指向言語 = JavaScript, Io等
手続き型言語の例(C言語)
void main(void) { printf("Hello World"); }
クラスがありません。
クラスベースオブジェクト指向言語の例(Java)
public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World"); } }
クラスがあります。
プロトタイプベースオブジェクト指向言語の例(JavaScript)
function HelloWorld() { } HelloWorld.prototype.main = function() { alert("Hello World"); }; var obj = new HelloWorld(); obj.main();
クラスの代わりにプロトタイプでオブジェクトを定義しています。
命令型と関数型
これまでに紹介した言語は全て命令型言語です。コンピュータに実行させる命令を順番に書いていくタイプの言語です。
それに対して関数型言語は、関数の作用を連鎖させて処理を進めます。
- 関数型言語 = Lisp, Haskell, OCaml, F#, Scala等
命令型と関数型の違いを見るために、FizzBuzzというかんたんなプログラムを書いてみましょう。
命令型言語(Java)でFizzBuzzの例
public class fizzbuzz { public static void main(String[] args){ int i = 1; while(i <= 100){ if(i % 3 == 0 && i % 5 == 0){ System.out.print("FizzBuzz"); } else if(i % 3 == 0){ System.out.print("Fizz"); } else if(i % 5 == 0){ System.out.print("Buzz"); } else { System.out.print(i); } if(i % 20 == 0){ System.out.println(); } else { System.out.print(" "); } i++; } } }
関数型言語(Haskell)でFizzBuzzの例
fizzbuzz :: Integer -> [String] fizzbuzz 0 = [] fizzbuzz n | n `mod` 15 == 0 = fizzbuzz(n - 1) ++ ["fizzbuzz"] | n `mod` 3 == 0 = fizzbuzz(n - 1) ++ ["fizz"] | n `mod` 5 == 0 = fizzbuzz(n - 1) ++ ["buzz"] fizzbuzz n = fizzbuzz(n - 1) ++ [show n]
関数型言語の方がコードが圧倒的に短いですが、直感的にわかりにくいですよね。そこが関数型言語の難しさですが、関数型言語をうまく使いこなせたら、すごく生産性が高いかもしれません。
違うパラダイムの考え方に触れると視野が広がる!
動的型言語を使ったら、静的型言語の良さが分かった
私は10年くらいJavaを使った後、PHP、Ruby等の動的型言語を使うようになったのですが、初めのうちは「動的言語だとコンパイルがないから正しい文法で書けたか不安でふわふわした感じ」がしたのですが、使っているうちに、
- コードのタイプ数が少なくてサクサク書ける
- コンパイルがないおかげで開発のテンポが良い
などの利点が分かり、今では動的言語の方が好きなくらいです。
また、動的型言語を学ぶことでJavaのような静的型言語の書き方にも変化がありました。動的型言語で、DBの1レコードを格納する際には、格納用のクラスを定義せず、連想配列や動的なオブジェクト(PHPだとstdClass)への格納を多用します。この習慣に慣れるとJavaでもわざわざ格納用クラスを作らなくてもいいかなと思うようになりました。もちろん、格納用クラスを作った方が良い場合もあるのでケースバイケースですけどね。
動的型言語を使うと静的型言語でならコンパイルで引っかかるようなコーディングのミスが実行時に見つかることがよくあり、静的言語コンパイラのありがたさを再認識することにもなりました。
シングルスレッドでもIOを待たなければ同時アクセスがさばける!?
言語以外にも違うパラダイムの考え方に触れると視野が広がります。
node.jsのシングルスレッドノンブロッキングIOアーキテクチャの話を初めて聞いたときには衝撃を受けました。
それまで私はサーバに対して同時に複数のリクエストが来た際にはマルチスレッドじゃないさばけないと思っていました。それ以外の方法などあるわけがないと思っていました。
しかし、node.jsでは、スレッドが一つしかありません。例えば、3つのリクエストが同時に来た場合には、
- リクエスト1の処理を進めて、ファイルやDBアクセスなどのIOが発生したら、IOが終わるのを待たずに、リクエスト2の処理に移ります。
- リクエスト2の処理もIOが発生したらリクエスト3の処理を開始します。
- そうやってる内にリクエスト1のIOが終わったら、続きの処理を行います。
こうやって、IO待ちしている間に別リクエストの処理を実行すれば、シングルスレッドでも同時アクセスをさばけるのです。
これには驚いたと同時に、同じ考え方の技術を使い続けていると頭が固くなって視野がせまくなることを痛感しました。
様々なタイプの言語を使って視野を広げよう
プログラミング言語には複数のタイプがあり、それぞれに特徴があり、様々なタイプの言語を使うことで考え方の幅や視野が広がります。
様々なタイプの言語をぜひ使ってみてください!