0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

インタプリタとコンパイラ

 JavaはJITコンパイラ言語である。細かく言えば違うがRubyとの対比で考えるならそういう認識でおおよそ問題ない。コンパイラ系であるため実行速度はRubyに比較して圧倒的に速いが、毎度コンパイルしないと実行できない不便さはある。
 対してRubyはインタプリタ言語である。コンパイラを通さずに直接実行できるが、毎回コードを評価する必要があるため実行速度ではJavaに劣る。その分、簡単なコードを手軽に実行できる身軽さがある。

堅牢性と自由さ

 Javaは非常に厳密で堅牢性の高いコードを書ける言語である。コンパイラという検問所が徹底的にコードを走査するため少なくとも文法上誤ったコードを書くことは許されない。そのため結果としてオブジェクト構造の視認性は極めて高い。
 Rubyは自由で簡潔なコードを書ける言語である。そこには堅牢さのかけらも無いが、だからこその自由がある。そして自由とは自己責任である。Javaのように怒ってくれるお母さんはいないので、プログラマは自分だけの力で安全なコードを書かなくてはならない。
 喩えるならJavaはグランツーリスモやForza Horizonなどのゲームでレースをするようなものだ。どんなに酷い運転をしてもあくまでゲーム、画面の中の車がひしゃげてもプレイヤーには何の影響も無い。対してRubyは生身の人間がハチロクで峠を攻めるようなものだ。レースゲームのようなイカれた速度は出せないがその体感がダイレクトに自分に返ってくる楽しさがある。しかしハンドル操作を誤れば大怪我ではすまない。

言語適正

 Javaはその堅牢性ゆえにある程度レベルの低いメンバーでもそれなりに安全なコードを書けるのでチーム開発に向いている。そして一見難しそうな見た目とは裏腹にむしろ初心者向けの言語である。怖い監督がいつも隣で目を光らせているからだ。
 Rubyはその自由さゆえにある程度レベルの高いメンバーでなければ安全なコードを書くことができない。隣がハンドル操作を誤ればチームメンバーも一緒に崖下である。ゆえに個人開発に向いている。そして一見簡単そうな見た目とは裏腹にむしろ上級者向けの言語でもある。

比較対象 Java Ruby
速度 比較的速い 比較的遅い
コンパイルの手間 ある ない
堅牢性 高い 低い(無い)
開発現場 チーム開発向け 個人開発向け
対象レベル 初心者向け 上級者向け

 つまり理想を言えば、Javaでオブジェクト指向と堅牢なアプリケーションの基礎を学び、チーム開発を経て可読性やドキュメントの重要性を学び、ある程度プログラミングに習熟したプログラマがコンパイラや開発チームという枷から解き放たれて、Rubyという自由な世界で自分の力を十全に発揮してその混沌を切り開いていく、というのが最適解と言える。

Java経験者がRubyのために最初に覚えるべき事

Rubyは全てがオブジェクト

  • つまりリテラルもオブジェクトである。truefalseもそれぞれのクラスのインスタンスとして実装されている。
  • nullに該当するのはnilである。nilもNilClassのインスタンスである。つまりnullと異なり実体がある。
  • これはつまりRubyにはプリミティブ型が存在しない事を意味する。1nilからメソッドを呼び出す事も可能である。

Rubyでの真偽値

  • Rubyではfalsenilのみがfalse、それ以外は全て(0""[]もあらゆるオブジェクトが)trueである。
  • Rubyにはboolean型やBooleanクラスが存在しない。ある意味で全てのオブジェクトがbooleanとして扱えると言える。これはRubyの強力な特徴である。

Rubyのクラス名は定数

  • 定数は値を持つ。つまりクラス名定数も値を持つ。
  • クラス名定数の値はClassオブジェクト(つまりClassクラスのインスタンス)である。

Rubyのself

  • selfはJavaのthisに該当する。thisと異なりクラス定義内(Javaでいうstatic初期化ブロック)を含め、あらゆる場所で使用できる。

Rubyのインスタンス変数、クラス変数

  • Rubyのインスタンス変数はJavaでいうインスタンスフィールドに該当する。クラス変数はstaticフィールドに該当する。
  • Javaと異なり変数のスコープは変更できない。Javaのprivateprotectedの中間ぐらいで固定。
  • publicにアクセスする事はできないので、アクセサなどでゲッターやセッターを定義する必要がある。

Rubyは型宣言が不要

  • 異なる型での上書きも可能。
  • メソッドのシグネチャも型情報が含まれないためメソッドの判別ができない。つまりオーバーロード機構が存在しない。

Rubyの演算子のほとんどはメソッドとして実装されている

  • つまり演算子の左辺と右辺で明確に意味が異なる。
  • 演算子メソッドはほとんどの場合 left_side_obj.operator_method(right_side_obj) として評価される。例外的に !メソッド はオブジェクトの前に置くことを許される。逆に言えば !演算子 は通常のメソッド呼び出しとしても書ける。(true.! == !true == false
  • 演算子メソッドを再定義することができるため、演算子の結果を変更する事ができる。

Rubyのオブジェクトは複数のインスタンスを持つ

  • self(自身のオブジェクト)とself.singleton_class(特異クラスオブジェクト)の2つのインスタンスを持ち、self.class(Classオブジェクト)への参照を持つ。
    • selfインスタンスがsingleton_classclassの二つのクラス参照を持つと言い換えても良い。どちらでも覚えやすい方で覚えて。
  • Classオブジェクトもオブジェクトなので当然、selfsingleton_classclassへの参照を持つ。
  • Javaではオブジェクトは、インスタンスとクラス情報(型)という組み合わせだが、Rubyでは全く異なる。

Rubyにはパッケージは存在しない

  • モジュールやクラスの名前空間をパッケージのように使うことができる。
  • モジュールの内部にクラス定義することで、ModuleName::InnerClassName の形で名前空間に所属できる。

Rubyにはインターフェースが無い

  • モジュールがインターフェースのようにも使える。
  • モジュールをincludeするとJavaのインターフェースのように継承関係を構築する。
  • abstractメソッドは定義できない。モジュールのインスタンスメソッドがインターフェースのデフォルトメソッドのように振る舞う。

Rubyにstaticメソッドは存在しない

  • 特異メソッドがその代替として使われる。
  • Rubyでクラスから直接メソッドを呼ぼうとした場合、クラスオブジェクトはClassクラスのインスタンスであるためClassクラスのインスタンスメソッドが探索されてしまいクラスに定義したインスタンスメソッドは探索されない。クラスに特異メソッドを定義すると、Classクラスのインスタンスメソッドの前に特異メソッドが探索されるので、Javaのstaticメソッドのように振る舞う事ができる。
  • staticメソッドを集めたstaticライブラリのような機能は、モジュールに特異メソッドを集める事で実現できる。
  • static import のようにも使いたい場合は特異メソッドをモジュール関数として定義し、includeすることで実現できる。

Rubyのイテレータ

  • Rubyは非常に強力な内部イテレータと完全なクロージャであるブロックを併用できるため、Javaの拡張for文のような外部イテレータはほとんど使われない。
  • そもそもイテレータが強力すぎてループ文自体がほとんど使われない。
  • Javaプログラマの観点ではイテレータは比較的使いづらい仕様であったが、Rubyのイテレータはブロック内で直接コードを書けるので直感的にわかりやすく非常に使いやすい。

Rubyのコレクション

  • Rubyのコレクションは実質的にArray、Hashの二種類しか存在しない。後期バージョンや拡張ライブラリではSetも使用可能だがSetの中身はキーのみのHashだ。
  • RubyのArrayはJavaのArrayList、HashはJavaのLinkedHashMapに相当する。
  • 実用レベルでは2種類で全く問題ない。逆に使い分けに悩む必要も無いので楽といえば楽。

Rubyのcase文はJavaのswitch文よりも高機能

  • case文の比較はwhenに与えられたオブジェクトの===メソッドで行われる。オブジェクトごとにその振る舞いを変更できる。
  • 例えば case v の時、when 1 なら v == 1 の場合に実行されるが、when Integer なら v.is_a?(Integer) の場合に実行される。
  • 評価式(v)を省略した場合、when v.odd? のようにwhenに判定文を書けるため複雑な制御構造にも対応可能。
  • caseは最後に評価した値を返すため、評価結果で代入する値を変えるような式はシンプルに書ける。

Rubyのメタプログラミング

  • Javaのリフレクションよりも強力かつ柔軟なメタプログラミングが可能。
  • 逆に言えばそれだけ安全性が犠牲になっているので、Javaの堅牢性が好きな人には発狂モノかもしれない。そういうモンだと諦めて

Rubyはスコープを制御できない

  • Javaのprivateprotectedに相当するアクセス制御は存在しない。
  • Rubyで定義できるprivateprotectedは呼び出し制限(call limit)であり全くの別物。むしろアノテーションに近い。
  • とりあえずRubyには完全にprivateな変数やメソッドは存在しない事だけ覚悟しといた方が良い。そういうモンだと諦めて

RubyのfreezeとJavaのfinalは同じではない

  • Rubyのfreezeはオブジェクトの変更を禁止する。例えば配列の内容は変更できなくなるが、変数の上書き(再代入)は可能。
  • Javaのfinalは変数の再代入(上書き)を禁止する。例えば変数の中身の配列は変更可能。
  • 上記の通り、RubyのfreezeとJavaのfinalはむしろ真逆の性能をしている。
  • Javaで変更不可能なコレクションを定義する事はできるが、既存のコレクションを変更不可にする事はできない。
  • Rubyでは定数も再代入可能(つまりクラス名定数も再代入可能)である。警告こそ出るが代入自体は防がれない。そういうモンだと諦めて

一番重要な点

  • 厳密で堅牢なコードを書けるJavaと異なり、Rubyは自由で簡潔なコードを書ける言語である。
  • 設計思想が異なるため、RubyにJavaのような堅牢性のあるコードを求めるのは間違いだとはっきり言わせて欲しい。
  • Rubyに堅牢性求めるのはキーパーにキャッチャーのプロテクターをつけさせるようなもので、そんなアホな事をするよりもRubyの自由さを楽しむ方が健全である。

まとめ

警告
Javaは初心者向け!

警告!!
Rubyは上級者向け!

関連リンク

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?