GObject
GObject(ジーオブジェクト、GLib Object System)は、移植性の高いオブジェクトシステムと言語間の透過的相互運用性を提供するフリーなライブラリ(LGPL)である。GObjectはC言語で実装されており、他の言語ではバインディングによって利用可能となっている。
GLibとlibcにのみ依存しており、GNOMEの基礎として GTK、Pango、Accessibility Toolkit、多くのGNOMEライブラリやアプリケーションなど広範囲に利用されている。GTK 2.0以前は、GObjectのコードはGTK+の一部だった。ただし、当時はGObjectとは呼ばれておらず、ベースクラスは GtkObject と呼ばれていた。
GTK 2.0リリースの際に、オブジェクトシステムを汎用ユーティリティとすべく、別ライブラリとして分離した。その際にGUI関係でない GtkObject クラスの大部分は新たなベースクラスである GObject に移された。GTK 2.0のリリースされた2002年3月11日以降、GObjectは独立したライブラリとして存在し続け、現在ではGUI以外のCUIアプリケーションやサーバアプリケーションにも広く使われている。
GObjectのマニュアル等はGLibとは別にあり、ライブラリファイルとしても別になっているが、ソースコードはGLibのソースツリー内にあって、GLibと共に配布されている。このため、GObjectのバージョン番号はGLibのものを使っており、GLibパッケージの一部とされることが多い(例えば、DebianではGObjectを libglib2.0 パッケージファミリに入れている)。
GObjectフレームワークの基盤として、汎用の動的型システム GType がある。GTypeシステムは全オブジェクトの実行時記述を保持し、各種言語バインディングを実現するグルーコードからそれを使うことができる。型システムは任意の単一継承クラス階層を扱え、同時にクラスでないデータ型も扱える(不透明ポインタ、文字列、各種サイズの整数と浮動小数点数など)。
GTypeは登録されている型に属する値のコピー、代入、破棄の方法を知っている。整数などの型ではこれらは自明だが、複雑なオブジェクトには参照カウントがあるものもあれば、(一部だが)参照カウントのないものもある。型システムが参照カウントのあるオブジェクトを「コピー」するとき、一般に単に参照カウントをインクリメントするだけである。しかし、参照カウントのないオブジェクト(例えば文字列)のコピーでは、メモリを確保して実際にコピーを生成する。
この基本機能を使って GValue が実装されている。これは汎用コンテナ型であり、型システムが把握している任意の型の値を保持できる。このようなコンテナは、全てのネイティブ値をそのような型タグコンテナに格納する動的型付き言語とやりとりする際に特に便利である。
クラスと関連のない型を non-classed と称する。そのような型と何らかの rootクラスに対応した全ての型を総称して「基本型」と呼び、それ以外の型を「派生型」と呼ぶ。これらは比較的閉じた体系であり、一般ユーザーが独自の基本型を生成することはないものと想定されているが、生成は可能であり、GObject クラスに基づかないクラス階層を独自に作ることもできる。
GLib 2.9.2では、non-classed の基本型は以下の通りである。
空の型、C言語の void に対応。(G_TYPE_NONE)
C言語の char、int、long、64ビット整数に対応した型。(G_TYPE_CHAR, G_TYPE_UCHAR, G_TYPE_INT, G_TYPE_UINT, G_TYPE_LONG, G_TYPE_ULONG, G_TYPE_INT64, G_TYPE_UINT64)
ブーリアン型。(G_TYPE_BOOLEAN)
列挙型とフラグ型。C言語の enum に対応するが、後者はビットフィールドにのみ使われる。(G_TYPE_ENUM, G_TYPE_FLAGS)
IEEE 754の単精度および倍精度の浮動小数点数。C言語の float と double に対応。(G_TYPE_FLOAT, G_TYPE_DOUBLE)
文字列型。C言語の char * に対応。(G_TYPE_STRING)
不透明ポインタ型。C言語の void * に対応。(G_TYPE_POINTER)
classed の基本型は以下の通りである。
標準クラス継承ツリーのrootである GObject のインスタンスの基底クラス型。(G_TYPE_OBJECT)
基底インタフェース型。標準インタフェース継承ツリーの rootを表している。(G_TYPE_INTERFACE)
ボックス化用の型。単純な値オブジェクトや外部オブジェクトを参照カウント付きの「ボックス」で包むのに使われる。(G_TYPE_BOXED)
「パラメータ記述オブジェクト(parameter specification object)」用の型。オブジェクトのプロパティのメタデータを記述するのに使われる。(G_TYPE_PARAM)
型システムによって自動的にインスタンス化できる型を instantiable と称する。そのような型の重要な特徴は、インスタンスの先頭数バイトに必ずその型に対応したクラス構造(一種の仮想関数テーブル)へのポインタが格納されている点である。このため、instantiableな型は必ずクラスと対応している。逆にnon-classedな型(整数や文字列)は instantiableではない。また、classedな型はインタフェース型などを除いてinstantiableである。
GObjectの組み込みの基本型から派生する型は4種類に分けられる。
オブジェクトシステムとの関連で何らかの形で使われる列挙型や整数ベースのビットフィールド型(すなわち、全ての enum 型)。例えば、オブジェクトのプロパティの型など。一般にこれらの型の登録を行う初期化コードは glib-mkenumsというツールで自動生成され、別ファイルに格納される。
完全なクラス型にするには単純すぎるデータ構造だが、型システムに登録する必要があるもの。例えば、あるクラスに background-color というプロパティを追加したいとする。その値は struct color { int r, g, b; } のようなデータ構造のインスタンスである。これを GObject のサブクラスにしたくない場合、ボックス化型で表し、コピーや解放といった機能を提供できる。GObjectにはGLibの単純なデータ型を包んだ各種ボックス化型が最初から備わっている。ボックス化型は、外部オブジェクトのタグ付きコンテナとしても使える。
場合によっては、コピーや解放といった機能も不要で、ボックス化型でも大げさすぎるというオブジェクトもある。そのようなオブジェクトは単に不透明ポインタ (G_TYPE_POINTER) として扱っても良いが、派生ポインタ型を生成することで、それがある特定用途のオブジェクトであることを示すことができる。
GObjectアプリケーションにおける大半の型はクラス型であり、通常のオブジェクト指向的な感覚で言えば、rootクラス GObject から直接または間接的に派生する。Java風のインタフェースもあるが、2006年現在ではあまり使用されていない(2004年3月16日にリリースされたGLib 2.4あたりで導入された新機能であるため)。GIMPはGObjectのインタフェース型を使っている。
GObjectのメッセージングシステムは、相補的な closure と signal から構成される。
コールバックを一般化したもの。C言語とC++以外にもバインディングがある言語から使える。例えば、PythonやJavaのコードをClosureの機構で GObjectから呼び出すことができる。
Closureを呼び出す一次機構。オブジェクトは、あるSignalとClosureのマッピングを指定したSignalリスナーを登録する。登録されたSignalが発信されると、対応するClosureが呼び出される。GTKでは、全てのネイティブGUIイベント(マウスの動きやキーボード操作)はGObjectのSignalを発信でき、対応するリスナーがそれに対して動作する。
GObjectのクラスはクラス構造体とインスタンス構造体という少なくとも2つの構造体で実装される。
C++におけるvtableに相当する。先頭にスーパークラスのクラス構造体がある。その後に関数ポインタ群があり、それぞれがクラスの仮想メソッドを指している。クラス固有変数を使って、クラス変数をエミュレートできる。
オブジェクトのインスタンス毎に存在する。先頭にスーパークラスのインスタンス構造体がある。その後にインスタンス固有の変数群があり、C++のメンバ変数に対応する。
C言語の構造体には“public"、“protected"、“private"といったアクセス修飾がないので、インスタンス構造体にプライベートデータへのポインタ _priv がある。プライベート構造体は共通ヘッダファイルに宣言することはできるが、定義は個々の実装ファイルでのみ行われ、外部から見えないようにしている。プライベート構造体をGTypeに登録すると、自動的にオブジェクトシステムで確保される。プライベートデータが必要なとき常に G_TYPE_INSTANCE_GET_PRIVATE を使うようにすれば、_priv ポインタを構造体に含める必要はない。
GObjectフレームワークの欠点は、冗長性である。新たなクラスを生成するとき、型登録や各種マクロを多量にコーディングする必要があり、その多くは決まりきった形式である。GObject BuilderやGOB2はこの問題に対処するツールであり、Java風の構文からコードを生成できる。GOB2で書かれたコードはコンパイル前にC言語のコードに展開される。他にもC#風の文法でコーディングできるValaがある。
C言語とGObjectを使っているフリーソフトウェアプロジェクトとしては、GNOMEデスクトップ、GTKツールキット、GIMP画像編集プログラムなどがある。
GObjectを使ったアプリケーションはC言語で書かれていることが多いが、GObject自体はC++、Java、Ruby、Python、.NET/Monoなどのオブジェクトシステムともうまくマッピングできる。従って、GObjectフレームワークを使ったライブラリに言語バインディングを作るのは比較的簡単である。
しかし、C言語でGObjectのコードを書くのは若干大変である。特に高級オブジェクト指向言語に慣れたプログラマにとっては苦痛かもしれない。例えば、ちょっとしたサブクラスを書くだけで数百行のコードを必要とする。とはいうものの、GObjectを使うことでC言語でオブジェクト指向的なコーディングが可能となる。
一級オブジェクトは存在しないが(GTypeにはメタタイプがない)、GObjectアプリケーションは実行時にクラスやインタフェースのようなメタオブジェクトを生成でき、イントロスペクションもサポートできる。この機能は言語バインディング以外にGladeなどのGUI設計アプリケーションで使われ、GObjectクラスを提供する共有ライブラリをロードし、そのクラスの全プロパティの一覧を獲得し、型情報とドキュメンテーション文字列を完成させるといったことが可能となる。
GObjectはC言語での完全なオブジェクトシステムであり、C言語から派生したC++やObjective-Cと同等のものと見ることもできる(ただし、C++はオブジェクトシステム以外にも様々な機能がある)。C++とGObjectの明らかな違いは、GObjectが多重継承をサポートしていない点である。
もう1つの重要な違いは、C++やObjective-Cが独立した言語であるのに対して、GObjectは単なるライブラリであり、新たな構文やコンパイラ機能を追加しているわけではないという点である。例えば、GObjectベースのコードを書くとき、明示的な cast が頻繁に必要となる。従ってGObjectとC言語の組合せを通常のC言語とは別の言語と考えたとき、それはC++とは異なり、通常のC言語の厳密なスーパーセットとなっている。
C++コンパイラを対象とした標準ABIは存在しないので(例外としてWindowsではCOMがその役割を担っている)、あるC++コンパイラでコンパイルされたライブラリから、別のC++コンパイラでコンパイルされたライブラリを呼び出せないことがある。そのような互換性を必要とする場合、C++メソッドはC言語の関数としてエクスポートされる必要があり、C++のオブジェクトシステムが部分的に破綻する。原因の一部は、C++コンパイラがエクスポートするシンボルの一意性を保証するために、それぞれ独自に名前修飾しているためである。一方これとは対照的に、C言語にはオーバーロードも名前空間もないので、C言語ライブラリではエクスポートされるシンボルの一意性を保証するために明示的なプレフィックスを付けるのが一般的である。GObjectベースのライブラリはオブジェクト指向ではあるがC言語で書かれているので、コンパイラが何であっても明示的なシンボル名を使う。
おそらく最も意義のあるGObjectの特徴はSignal(他の言語ではイベントと呼ばれる)である。これは、GObjectがGUIツールキット向けに開発されたために必要になった機能である。他のオブジェクト指向言語にも同様の機能はあるが、GObjectではオブジェクトシステムそのものに組み込まれている。このため、GObjectアプリケーションはSignalを多用する傾向があり、GObjectのコンポーネントはC++やJavaよりもカプセル化とコードの再利用という面で優れている。