Метакласс
Метакласс (англ. Metaclass) — в объектно-ориентированном программировании это класс, экземпляры которого в свою очередь являются классами[1][2].
Поддержка языками программирования
Не все объектно-ориентированные языки программирования поддерживают метаклассы. Те из них, что поддерживают, реализуют разный подход со своими собственным протоколом, правилами создания и обращения[3].
Среди языков, поддерживающих метаклассы:
- Common Lisp и Dylan в составе CLOS
- Groovy
- Object Pascal (особенно Embarcadero Delphi)
- Objective-C
- Python
- Perl, через модуль Moose
- Ruby
- Java
- Smalltalk
Кроме того, существует целый ряд узкоспециализированных, особенно так называемых «академических» языков программирования, поддерживающих и исследующих концепцию метаклассов[4].
Особняком стоит Java, где также есть единственный метакласс — Class (описывает классы), который располагается в библиотеке java.lang. Однако, развитой концепции работы с метаклассами Java не предоставляет.
Поддержка платформами
Метаклассы могут существовать не только как сущность языка программирования, но и как сущность многоязыковой платформы. Наиболее явно метаклассы выражены в IBM System Object Model. Архитекторы SOM учитывали положительные стороны CLOS и решили один из её недостатков, несовместимость метаклассов, уникальным на то время способом. Несовместимость метаклассов — это ситуация, когда метакласс подкласса не является подклассом метакласса. В CLOS это приводит к аварийному завершению. Ситуация может возникнуть, когда разные части системы разрабатываются разными командами, и структура классов одной части системы изменилась, а в другой части системы эти изменения не синхронизированы. Одной из целей SOM являлось обеспечение максимальной совместимости на бинарном уровне между релизами. Инновационным решением, введённым в SOM 2.0 является создание анонимного подкласса нескольких метаклассов в случае, если ни один из метаклассов класса не является подклассом для остальных. В CLOS и SOM 1.0 указание метакласса является требованием. В SOM 2.0 указание метакласса является пожеланием, а реальный метакласс может быть создан во время исполнения, наследуясь от нескольких родителей: от желаемого метакласса, а также от метаклассов каждого надкласса.
Явные и неявные метаклассы
Явные метаклассы указываются при объявлении класса. Разработчик, имея возможность явно указать метакласс, может создавать произвольно сложные иерархии.
Если объектная модель поддерживает только неявные метаклассы, это значит, что синтаксически существует только иерархия классов, но при этом в классах присутствуют так называемые классовые методы. При этом иерархия метаклассов зеркалирует иерархию классов. Обычные методы добавляются в обычный класс, а классовые методы добавляются в соответствующий метакласс, но разработчик не может установить произвольные связи наследования между метаклассами и классами. Классовые методы могут быть настоящими методами, а могут быть «синтаксическим сахаром», то есть, видны, если обращаться к классу по имени, но не видны, если пытаться вызвать их как обычные методы у переменной, которой перед этим была присвоена ссылка на этот же класс.
Зацикленность метаклассов
Цепочка из классов классов классов … в разных объектных моделях ведёт себя по-разному.
В моделях с неявными метаклассами поддерживается зеркалирование иерархий, а, значит, и разделение. Так, в Delphi метаклассы не могут иметь собственное имя, а всегда идентифицируются как «class of …», а поскольку «class of class of …» — синтаксически неверная конструкция, то цепочка заведомо обрывается на метаклассе. В SmallTalk и Objective-C классы, хотя и неявные, но всё же являются объектами, аналогичными обычным, поэтому оборвать цепочку невозможно.
В моделях с явными метаклассами классы — это объекты, поэтому оборвать цепочку тоже невозможно. Если цепочку не обрывать, либо должен существовать специальный базовый класс, сконструированный так, чтобы являться классом для себя самого, либо эта цепочка потенциально бесконечна с созданием очередных метаклассов на лету.
Несовместимость метаклассов
Несовместимость метаклассов — это ситуация, когда метакласс подкласса — не подкласс метакласса. То есть, может существовать какой-то код, работающий с экземплярами класса A, про который известно, что его класс (метакласс его экземпляров) — это класс MA, и у любого объекта класса A можно вызвать классовые методы из MA. Тогда, если вдруг возможно создать экземпляры потомков класса A, не поддерживающих классовые методы из MA, такие экземпляры потомков будут несовместимы с кодом, ожидающим экземпляры A, что противоречит принципам ООП. Чтобы такие скрытые ошибки не происходили, обычно создание таких потомков блокируется.
В моделях с неявными метаклассами за счёт зеркалирования иерархий такая ситуация в принципе исключена. В моделях с явными метаклассами можно либо аварийно завершить программу, либо сконструировать такой метакласс, который был бы потомком для метакласса каждого базового класса и для желаемого метакласса класса. Конечно, для этого необходима поддержка множественного наследования.
Сравнение особенностей
Объектная модель | C++ | Delphi | Java и .NET | SmallTalk и Objective-C | Ruby | CLOS | Python | SOM и PMtW[5] |
---|---|---|---|---|---|---|---|---|
Метаклассы явные? | RTTI | неявные | неявные | неявные | ? | явные | явные | явные |
Класс — это обычный объект? | нет | нет | да | да | ? | да | да | да |
Классовые методы — это методы класса? | нет | да | нет | да | да | да | да | да |
Цепочка из классов классов классов … | обрывается | обрывается | зациклена | зациклена | бесконечна | зациклена | зациклена | зациклена |
Если метакласс подкласса — не подкласс метакласса, то | н/п | н/п | н/п | н/п | ? | ошибка | ошибка | нужный конструируется |
Примечания
- Мейер, Бертран «Основы объектно-ориентированного программирования»
- Wolfgang Klas, Michael Schrefl Metaclasses and Their Application. Data Model Tailoring and Database Integration. — Berlin; Heidelberg; New York; Barcelona; Budapest; Hong Kong; London; Milan; Paris; Tokyo : Springer, 1995 (Lecture notes in computer science; Vol. 943) ISBN 3-540-60063-9
- Ira R. Forman and Scott Danforth Putting Metaclasses to Work — 1999. ISBN 0-201-43305-2.
- Noury Bouraqad Efficient Support for Mixin-Based Inheritance Using Metaclasse Архивная копия от 16 октября 2007 на Wayback Machine.
- Модель, описанная в книге «Putting Metaclasses to Work» и реализованная в прилагаемой к книге симуляции на Java (для запуска требуется старый JDK).
Литература
- И. Ю. Баженова, «Delphi 7 самоучитель программиста», «Москва» 2003