C・C++からRubyへ

C・C++とRubyとで、あなたのコードがどう変わるのかを示すのは容易ではありません。 ものすごく大きな違いがあるからです。 一つには、Rubyの実行環境が本当にたくさんのことを行うという違いがあります。 RubyはC言語の「機構側は何も隠蔽しない」という原則からはかけ離れた言語のように見えます。 Rubyの本質は、人間の仕事を簡単にするために、できるだけ多くの作業を実行環境が肩代わりすることにあります。 最適化するためにコードをプロファイリングするようになるまでは、Rubyを使う際にコンパイラ側の都合を気にする必要はありません。

とはいうものの、C・C++で書かれたコードの実行時間と比べて、Rubyコードの実行時間はずっと遅いと言われています。 そのため、どうしたら最小のコードでやりたいことを実現できるかを考えると同時に、 それを高速化する方法についても、あなたは頭をフル回転させることになるかもしれません。 RubyはC++よりもずっとずっとシンプルな言語です。Rubyはきっとあなたのことを甘やかすことでしょう。

Rubyは動的型付けです。静的型付けではありません。 Rubyの実行環境は、なるべく多くのことをプログラム実行時に行おうとします。 たとえば、どのモジュールをRubyプログラムにリンクする(ロードして使えるようにする)かや、どのメソッドを呼び出すかを、 あなたはあらかじめ知る必要はありません。

幸いなことに、RubyとCは堅実に共生関係を持つことができます。 Rubyはいわゆる「拡張ライブラリ」という仕組みをサポートしています。 拡張ライブラリは、Rubyプログラムから使用することができるものですが、Cで書かれます (外側から見ると、それはRubyで書かれたライブラリと同様に振る舞います)。 この仕組みを使うと、Rubyプログラムの中でパフォーマンスが重要となる部分を、純粋なCで書き直すことができます。

そしてもちろん、Ruby自体もCで書かれています。

Cとの類似

Cと同様に、Rubyは…

  • 書きたいと思えば、手続き的にプログラムを書くことができます(けれど、その裏側はオブジェクト指向のままです)。
  • 使用できる演算子は、複合代入子やビット演算子も含めて、だいたい同じです。ですが、Rubyには++--はありません。
  • __FILE____LINE__を使えます。
  • 定数もあります。けれど、constのような特別なキーワードはありません。 定数化は名前付けによって行われます。変数名の最初が大文字のものは定数として扱われます。
  • 文字列は二重引用符(")で括ります。
  • 文字列は可変です。
  • manページのように、ターミナルからほとんどのマニュアルを読むことができます。ただ、その際に使うコマンドはriです。
  • これまでと同じコマンドラインデバッガを使うことができます。

C++との類似

C++と同様に、Rubyは…

  • 使用できる演算子はだいたい同じです(::もあります)。<<はリストに要素を追加するためによく使われます。 Rubyではメンバ関数の呼び出しに->は使いません。常に.を使うので、この点には気をつけてください。
  • publicprivateprotectedなどを使います。
  • 継承を一文字で表現できます。ですが、使うのは:ではなく<になります。
  • コードをモジュール化することになりますが、これはC++でnamespaceを使うことと変わりません。
  • 例外を扱うための作法は一緒です。ですが、そのために使われるキーワード名などには違いがあります。

Cとの違い

Cと違って、Rubyは…

  • コードをコンパイルする必要はありません。単に実行するだけです。
  • オブジェクトは強く型付けされています(そして、変数名自身はまったく型を持ちません)。
  • マクロやプリプロセッサはありません。キャストもポインタ(とポインタ演算)もありません。 typedef や sizeof、列挙型もありません。
  • ヘッダファイルはありません。ただ関数(「メソッド」と呼ばれます)とクラスをソース内に記述するだけです。
  • #defineはありません。そのかわりに定数を使います。
  • すべての変数はヒープ上に配置されます。あなたがそれを解放する必要はありません。代わりにGCがその世話をしてくれます。
  • メソッド(関数)の引数は値渡しされます。参照渡しはされません。
  • #include <foo>#include "foo"の代わりに、require 'foo'と書きます。
  • アセンブリコードに変換はできません。
  • 行の終わりにセミコロンは不要です。
  • ifwhileなどの条件式は、括弧を付けなくても動きます。
  • メソッド(関数)呼び出しの括弧は基本的にオプションです。
  • 波括弧はあまり使いません。複数行に渡る処理片の終わりには、一般的にendキーワードが使われます。
  • doキーワードは「ブロック」と呼ばれる機能のためにあります。Cにおける「do命令」ではありません。
  • 「ブロック」はC言語にあるブロックとは別ものです。 Rubyのブロックは、メソッド呼び出しに関連付けるコード片を意味します。 ブロックは、メソッドの本体から実行時に呼び出されます。
  • 変数宣言はありません。変数が必要になったら、新しい変数名に紐付けるだけです。
  • 真偽値をテストする際、falsenilだけが偽と評価されます。他(00.0"0"なども)はすべて真となります。
  • charはありません。単なる一文字だけの文字列になります。
  • 文字列の終端はヌル文字ではありません。
  • 配列リテラルは角括弧です。波括弧ではありません。
  • 要素を追加すると、配列の大きさは自動的に拡張されます。
  • 二つの配列を足し合わせると、新しい大きい配列が返されます(もちろん、ヒープ上に割り当てられます)。ポインタ演算は行われません。
  • だいたいの場合は、すべてが式です(while命令が実際に右辺値を評価しているなど)

C++との違い

C++と違って、Rubyは…

  • 明示的に参照を扱うことはありません。 Rubyでは、すべての変数はあるオブジェクトへの間接参照として扱われます。
  • オブジェクトは強い型付けがされますが、それは動的に行われます。 環境は実行時、メソッド呼び出しが実際に行われたタイミングで型を決定します。
  • コンストラクタは、クラス名ではなく、initializeメソッドとなります。
  • メソッドはすべて仮想関数です。
  • クラス変数(静的メンバ変数)名は、常に@@からはじまります(例えば@@total_widgetsというように)。
  • 外部からメンバ変数に直接アクセスすることはありません。 publicなメンバ変数(Rubyでは属性と呼ばれます)へのアクセスはメソッド経由で行います。
  • thisの代わりにselfを使います。
  • 最後が?や!で終わるメソッドがあります。これらは実際にメソッド名の一部です。
  • 多重継承はありません。Rubyでは代わりにMix-inを使います。 Mix-inを用いることで、モジュールが持つすべてのインスタンスメソッドを「継承」できます。
  • 大文字表記、小文字表記が強制されるケースがあります。たとえば、 クラス名は大文字から開始し、変数名は小文字から開始する必要があります。
  • メソッド呼び出しの括弧は基本的にオプションです。
  • いつでもクラスをオープンしてメソッドを追加できます。
  • どんな種類のオブジェクトでも変数に設定でき、型は実行時に評価されるので、 C++テンプレートは必要ありません。キャストもありません。
  • イテレーションはわずかな違いがあります。 Rubyでは、vector<T>::const_iterator iterのような独立したイテレータオブジェクトは使いません。 代わりに、コンテナオブジェクトが持つeachなどのイテレータメソッドを使います。 イテレータメソッドはコード片を受け取り、それを各要素へと順に渡していきます。
  • コンテナクラスはArrayHashの2種類だけです。
  • 型変換はありません。Rubyを使い始めれば、必要ない理由がわかるはずです。
  • マルチスレッド機能は組み込まれています。 ただし、Ruby1.8 以前のマルチスレッド機構は、ネイティブスレッドに対してグリーンスレッドと呼ばれ、 処理系だけで実装されたスレッド機能になっています。
  • ユニットテストのライブラリはRubyに標準添付されています。