Mixin

MixinまたはMix-inは、オブジェクト指向プログラミングで用いられる技法であり、他のクラスから使用されるメソッド群を持つクラスが、他のクラスのスーパークラスにならないで済むための、特別な多重継承関係を実現するためのメカニズムを意味している。Mix-inされたメソッドに、他のクラスがアクセスする方法はそれぞれの言語仕様に依存している。

Mix-inはコードの再利用性を促進し、従来のクラスの多重継承がもたらしていた菱形継承などの数々の問題を回避する。多重継承を採用していない言語においては、多重継承と類似の機能性をより堅牢にして提供する。依存性逆転の原則のデザインパターンにも応用されている。

1. 概要
-----

Mix-inの理念は、クラスに機能を注入することである。機能ユニットをクラスとして表現して、それを他のクラスにミックスできるようにすることである。機能ユニットはメソッドの集合体にされることが多い。Mix-inは、UMLクラス図にある汎化/特化および実現/実装の双方に該当しない継承の種類を表わしている概念であり、それはニーズ/インクルードとも言われる。Mix-inの各言語での導入方法は非常に多様化しているので、その用法は曖昧である。

Mix-inクラスは、多重継承されることを前提にして、上位クラスのように振る舞って自身が内包する機能性を提供し、下位クラスはその機能性を利用する権利を得るが、その特化の義務までは負わない。特化とはUMLクラス図のそれであり、Is-a関係や派生がそれに該当している。Mix-inクラスの継承関係では、上位基底よりも親、下位派生よりも子と言った方が適当になる。

Mix-inクラスの代表的形態はトレイトである。トレイトの継承はインクルードと言う方が好まれる。言語によってモジュールプロトコルロールといった形態もあり、それぞれ微妙な機能の違いがある。Mix-inクラスと抽象クラスと具象クラスを一律化している言語もある。関数オブジェクトをトレイトとして扱える言語もある。型クラスをトレイト相当にしている言語もある。メソッド実装可能にしたインターフェースを事実上のトレイトにしてる言語もある。

Mix-inの利点は以下のようになる。

クラスの多重継承問題を回避しつつ、多様な機能性のみを利用できる。
Mix-inクラスによる機能の分類体系化によって、コードの再利用性を促進させる。
親クラスの特化の義務を負わずに、親クラスの機能をかいつまんで利用できる権利を得る。Mix-inの欠点は以下のようになる。

Mix-inの多用は機能中心のプログラムを招いて、データ中心のオブジェクト指向の本質から外れる。
Mix-in設計は煩雑になりがちであり、UMLクラス図の汎化特化設計および実現実装設計よりも品質が低下する。
Mix-inではメソッド決定順序がブラックボックス化しがちであり、結局これは多重継承問題と同類になる。

2. 来歴
-----

mixinは、そのようなもの自体はそれ以前からも考えられていたが、1970年代のMIT系Lisp方言のオブジェクト指向システムFlavors でその名が使われ、それが一般化した。Flavorsは、同時期のSmalltalkのオブジェクト指向システムに影響された試みのひとつであるが多重継承を特長とした。名称の由来は、マサチューセッツ州 Somerville にあったアイスクリーム屋からヒントを得て考え出されたものであるこのアイスクリーム店の店長は基本となる味を混ぜ、追加の具材と組み合わせたものを提供し、それを Mix-In と呼んで店の登録商標としていた。

mixinはコードの再利用を促進する。しかし、mixin にはそれなりの妥協も伴う。mixin は、「メソッド実装付きのインタフェース」ということもできる。クラスが mixin を含む場合、そのインタフェースを実装したクラスは、mixin の属性と操作を取り込む。継承するというのとは異なっている。取り込んだ要素はコンパイル時にクラスの一部となる。興味深いことに、mixin はインタフェースを実装する必要はない。それでもあえてインタフェースを実装する利点は、そのインタフェースを必要とするメソッドに、引数としてインスタンスを渡せるからである。

3. Mixinの導入言語
-------------

Mixinの原点は、MIT系Lisp方言オブジェクト指向システムのFlavors であり、その後継であるCommon Lisp オブジェクトシステム上の実装で広く知られるようになっている。日の丸言語RubyもMixinの採用言語として有名である。Mixinを採用している言語としては以下のものがある。

Ada - 総称型パッケージの特殊ディスパッチがそれに相当する
D言語 - テンプレート・ミックスインが導入されている
Dart
JavaScript - 関数オブジェクトがそれに相当する
Kotlin
OCaml
PHP
MATLAB
Racket
Raku - ロールとして導入
en - モジュールとして導入
Smalltalk
Swift - プロトコルとして導入
Vala
Object REXX

4. Mixinの例
----------

4.1. Python
-----------

Python の、特に Python 2.3 以降および Python 3 では C3 linearization により多重継承した際のメソッド探索順は解決されるので、多重継承は有力な手法であり、実際にいくつか活用例がある。SocketServer モジュールは UDP および TCP ソケットサーバとして動作する UDPServer と TCPServer クラスの両方を備えている。通常、すべてのコネクションは同じプロセス内で処理されるが、ForkingMixIn と ThreadingMixIn という追加の mixin クラスが存在する。下記のように TCPServer を ThreadingMixIn により拡張すると、

class ThreadingTCPServer: pass

ThreadingMixIn が TCPServer にコネクションごとにスレッドを生成する機能を追加する。あるいは、ForkingMixIn を用いると各新規のコネクションに対してプロセスが fork される。明らかに、スレッドを生成したりプロセスを fork する機能は単独では大して役に立たない。

この使用例では、mixin はソケットサーバとしての機能に影響することなく、基盤となる機能を選択可能な形で提供している。

4.2. C#
-------

C#ではインタフェースと拡張メソッドの組合せによって、Mix-inを再現できる。

using System.Linq;

System.Collections.Generic.IEnumerable range = Enumerable.Range; // IEnumerableにはSumメソッドは定義されない。 // 実際にはSystem.Linq.Enumerableクラスに実装された拡張メソッドである。 int sum = range.Sum;

// 上記は下記の糖衣構文である。 int sum = Enumerable.Sum;<WtXmlEndTag />

5. 関連項目
-------

トレイト
抽象型
Decoratorパターン
デリゲーション
多重継承
アスペクト指向

6. 脚注
-----

7. 外部リンク
--------

[1] at [2]
[3] in ActionScript.
[4] - a step-by-step example in Scala
[5] by Richard P. Gabriel and Linda DeMichiel provides a good introduction to the motivation for defining classes by means of generic functions.