System Object Model

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск
System Object Model (SOMObjects)
IBM SOMobjects Logo.png
Тип

программное обеспечение

Разработчик

CILabs (IBM, Apple Computer и др.)

Операционная система

Mac OS, OS/2, AIX, Windows, DOS

Последняя версия

3.0 (декабрь 1996 года)

System Object Model (SOM) — система объектно-ориентированных динамических библиотек, разработанная CILabs (IBM, Apple, OMG, Adobe, Oracle и др.). DSOM, основанная на CORBA распределённая версия SOM, позволяющая распределять объекты по различным вычислительным системам. Существуют реализации для Windows NT, MacOS Classic, OS/2, AIX, DOS, Copland, OS/390, NonStop OS. Для Windows NT, MacOS и OS/2 существует реализация компонентной разработки приложений OpenDoc на базе SOM/DSOM.

Сравнение с другими объектными моделями[править | править вики-текст]

Microsoft COM[править | править вики-текст]

IBM SOM концептуально похож на Microsoft Component Object Model. Обе системы решают проблему создания стандартного формата библиотеки, которую можно было бы вызывать из более, чем одного языка. SOM считается более функциональным, чем COM. COM предлагает два способа вызывать методы объекта, и объект может реализовать один из них или оба. Первый — это динамический вызов и позднее связывание (IDispatch), и, аналогично SOM, не зависит от языка программирования. Второй способ, через частный интерфейс, использует таблицу функций, которую можно сконструировать на C, либо использовать совместимую на нижнем уровне таблицу виртуальных методов объекта C++. Используя совместимые компиляторы C++, можно объявлять частные интерфейсы как чисто виртуальные классы C++. Частные интерфейсы — это компромисс между функциональностью и производительностью. Как только интерфейс опубликован в выпущенном продукте, в него нельзя вносить изменения, поскольку приложения–пользователи интерфейса были скомпилированы под конкретное устройство таблицы на нижнем уровне. Это пример проблемы хрупкого базового класса, которая может привести к DLL hell, когда после установки новой версии разделяемой библиотеки все программы, использующие старую версию, перестают работать корректно. Чтобы избежать этой проблемы, COM разработчикам необходимо всегда помнить о том, что нельзя изменять уже опубликованные интерфейсы. Если требуется добавить новые методы или внести другие изменения, нужно определять новые интерфейсы. SOM предотвращает эти проблемы, предоставляя только позднее связывание и позволяя компоновщику времени исполнения перестраивать таблицы на лету. Таким образом, изменения в нижележащие библиотеки пересчитываются при их загрузке в программы ценой небольшой потери производительности.

Интерфейс, однако, нельзя изменять не только по техническим соображениям, но и с точки зрения ООП. Интерфейс, в отличие от класса, не имеет реализации по умолчанию и при этом может быть реализован любым, в том числе сторонним разработчиком. Соответственно, если в интерфейс внесены изменения, то классы сторонних разработчиков не могут автоматически поддержать новый интерфейс. Таким образом, можно либо только применять классы вместо интерфейсов, предоставляя всегда актуальную реализацию по умолчанию, либо запретить сторонним разработчикам реализовывать потенциально подлежащий расширению интерфейс, но в этом случае слово «интерфейс» теряет свой смысл с точки зрения ООП.

SOM также более функционален в том, что касается полной поддержки различных ОО языков. В то время, как разработка на COM сводится к использованию урезанной версии C++, SOM поддерживает почти весь набор обычных возможностей и даже немного эзотерических. Например, SOM поддерживает множественное наследование, метаклассы и динамические вызовы. Некоторые из этих возможностей не отражены в большинстве языков, в связи с чем многие SOM/COM–подобные системы реализованы проще ценой поддержки меньшего набора языков. Полная гибкость многоязыковой поддержки была важна для IBM, в связи с необходимостью поддерживать как Smalltalk (одиночное наследование, динамическое связывание), так и C++ (множественное наследование и статическое связывание). Необходимость поддержки множественного наследования, помимо прочего, следствие того, что вместо интерфейсов есть только классы. Следует заметить, что поддержка множественного наследования в C++ отличается от CLOS, Dylan, SOM и Python, и проблемы множественного наследования в C++ не характерны для SOM.

Наиболее заметное отличие между SOM и COM — это поддержка наследования — у COM отсутствует вовсе. Может показаться странным, что Microsoft произвела систему библиотек объектов, не поддерживающую наиболее фундаментальный принцип ООП. Главным препятствием для этого является сложность определения нахождения базового класса в системе, в то время, как библиотеки загружаются в потенциально произвольном порядке. COM требует от разработчика точно указывать базовый класс на этапе компиляции, делая невозможной вставку других наследованных классов в середину (по крайней мере, в чужие библиотеки COM).

Напротив, SOM использует простой алгоритм, просматривая дерево наследования в поисках потенциального базового класса и останавливаясь на первом подходящем. В большинстве случаев это основной принцип наследования. Обратная сторона этого подхода — вероятность отказа работать новых версий базового класса, несмотря на неизменный API. Эта вероятность существует в любой программе, не только в использующих разделяемые библиотеки, но проблему становится очень сложно отследить, если она существует в чужом коде. В SOM единственное решение — это полное тестирование новых версий библиотек, что не всегда легко.

Другие системы[править | править вики-текст]

Сравнение с другими подходами было сделано в докладе «Release-to-Release Binary Compatibility and the Correctness of Separate Compilation» [1], в частности, были рассмотрены Smalltalk, CLOS, Generic C++, SOM, SGI Delta/C++, OBI, Objective-C, Java. Из современных систем наиболее близок к SOM с точки зрения обеспечения низкоуровневой сомвестимости Objective-C, особенно, после реализации non-fragile ivars.

Поддерживаемые языки программирования[править | править вики-текст]

C, C++[править | править вики-текст]

Эмиттеры для C и C++ входят в собственно поставку SOMobjects Developer Toolkit и позволяют как вызывать методы объектов, так и наследовать от классов. В некоторых компиляторах C++, сначала MetaWare High C++, потом IBM VisualAge C++, была реализована возможность Direct-to-SOM. В VisualAge C++ для Windows эта возможность появилась в версии 3.5[2], и эта же версия одновременно стала последней, в которой эта возможность поддерживалась.

REXX[править | править вики-текст]

ObjectREXX, поставляемый с OS/2, интегрирован с SOM, позволяет вызывать методы объектов и наследовать от классов. При передаче исходных текстов ObjectREXX сообществу open source все файлы, требуемые для функционирования этой интеграции, не были переданы, и в open source версию эта возможность не попала. Некоторое время в репозитории были следы интеграции с SOM, но скомпилировать было невозможно, а впоследствии всё, что было связано с SOM, было удалено совсем.

SmallTalk[править | править вики-текст]

Пакет SOMSupport для VisualAge SmallTalk позволяет вызывать методы SOM объектов и создавать SOM обёртки для классов SmallTalk.

COBOL[править | править вики-текст]

IBM ObjectCOBOL изначально использовал SOM как объектную систему в режиме Direct-to-SOM. Впоследствии ObjectCOBOL был перенесён на Java и начал пользоваться объектной системой Java вместо SOM.

Basic[править | править вики-текст]

В некоторых версиях VisualAge for Basic имелась интеграция с SOM[3]. Кроме того, Lotus Script, входящий в поставку OpenDoc, посредством OpenDoc Direct Scripting (ODDS) также может работать с SOM объектами[4].

Java[править | править вики-текст]

В SOMObjects Java Client[5] была возможность вызывать SOM объекты только удалённо, через DSOM. В примере с демонстрацией были классы, которые делались доступными на сервере DSOM, а затем Java апплет размещался на Интернет–ресурсе, создавал удалённые объекты и вызывал их методы. Локальный вызов методов не предусмотрен.

Pascal[править | править вики-текст]

Частным лицом были разработаны эмиттеры для Virtual Pascal, позже портированы на Free Pascal[6] (только OS/2). Позволяют вызывать методы и создавать свои классы.

Другим частным лицом был независимо разработан SOMIRIMP.exe[7] (только Windows), средство импорта из двоичной базы данных SOM.IR в привязки для Delphi. Позволяет вызывать методы, но не создавать классы. В отличие от предыдущего эмиттера, реализованного на C, SOMIRIMP написан на Delphi и использует привязки, сгенерированные им самим.

Ada[править | править вики-текст]

Разработчики компилятора PowerAda сделали эмиттеры[8] и примеры использования SOM. PowerAda был доступен только на AIX, и для запуска эмиттера нужен SOM 3.0 Beta, тоже для AIX. SOM 3.0 для AIX утерян.

Modula-2[править | править вики-текст]

Canterbury Modula-2 для OS/2 имела объектно–ориентированные расширения, аналогичные Oberon-2, и поддерживала режим компиляции Direct-to-SOM в профессиональной версии.[9]

Oberon-2[править | править вики-текст]

Oberon Мicrosystems анонсировала поддержку Direct-to-SOM на Mac OS Classic, но состояние этого проекта неизвестно.[10]

Способы интеграции с SOM[править | править вики-текст]

Эмиттеры[править | править вики-текст]

Обычно разработка для SOM происходит по следующей схеме:
В режиме потребителя:
Разработчик запускает компилятор SOM с эмиттером для желаемого языка программирования, указав, для каких файлов IDL желаемой библиотеки, делать привязки. Например: sc -sada somcm.idl Эмиттер создаёт один или несколько файлов в том формате, который понимает компилятор выбранного языка программирования. При помощи этих файлов становится возможным создавать объекты описанных классов и вызывать их методы.
В режиме производителя:
Разработчик пишет свои .idl файлы, в которых делается #include других .idl файлов, и от описанных в других .idl классов производятся наследники. Затем разработчик запускает специальный эмиттер, который создаст файлы с вспомогательным кодом и файлы с пустой реализацией методов класса.
Например: sc -sih animals.idl sc -sc animals.idl Первый вызов создаст animals.ih, который будет содержать, например, реализацию Animals_AnimalNewClass, которая запустит somBuildClass2, передав ей сложную структуру, синтезированную на основе входного .idl. Кроме этого вызова в этом файле есть сама эта структура и некоторые другие вспомогательные элементы, которые разработчик не должен изменять вообще. Второй вызов создаст animals.c с пустыми реализациями методов. Эмиттер C и C++ от IBM могут работать инкрементально, добавляя пустые новые методы, не трогая код существующих методов.

Кроме этого, есть эмиттеры для создания .dll. Эмиттер IMOD синтезирует главную функцию .dll, эмиттер DEF синтезирует .def и .nid файлы.

Эмиттер представляет собой библиотеку с названием emit*.dll, где * — это параметр аргумента -s компилятора SOM. Библиотека должна экспортировать процедуру emit (SOM 2.1) или emitSL (SOM 3.0), которая, будучи вызвана из компилятора SOM, выполняет работу, специфичную для выбранного эмиттера. Работа может быть любая. Для создания новых эмиттеров есть скрипт newemit.

База данных SOM Interface Repository[править | править вики-текст]

Среди эмиттеров есть эмиттер IR, создающий или обновляющий двоичную базу данных SOM.IR. Впоследствии эта база данных может быть открыта при помощи Interface Repository Framework. Это чаще всего применяется для удалённых вызовов процедур и динамических языков программирования. Таким образом работают VisualAge SOMSupport для Smalltalk и ObjectREXX.

Кроме того, стандарт OpenDoc включает в себя OpenDoc Direct Scripting (ODDS), и интерпретаторы сценарных языков программирования, реализующие интерфейс ODScriptComponent, могут тем самым обращаться к SOM классам посредством ODDS. Примером подобного языка программирования является Lotus Script, поставляемый в комплекте с OpenDoc[4].

База данных SOM.IR может быть использована и для создания привязок к компилируемым языкам программирования[11].

Интеграция SOM и COM[править | править вики-текст]

В Novell разработали мост, при помощи которого объекты SOM стали доступны из языков, поддерживающих OLE Automation. Кроме того, Novell ComponentGlue позволяет приложениям, использующим одну из технологий OLE или OpenDoc, задействовать компоненты, сделанные по другой технологии, а также оформить OpenDoc part как компонент OLE (OCX). При этом используется утилита ctypelib. При использовании этой утилиты никакого программного кода во время компиляции не создаётся. В реестре регистрируется одна и та же DLL из состава OpenDoc, которая способна загрузить в память библиотеку SOM и создать во время выполнения таблицы виртуальных методов, трамплины и другие элементы, необходимые для прокси–объектов COM. Обычно ComponentGlue реализует только интерфейс IDispatch, но, чтобы ускорить работу, существует возможность объявить и реализовать собственный COM интерфейс, если пометить интерфейс SOM модификатором ODdual и привести в соответствие всем правилам для OLE интерфейсов.

Другим средством интеграции SOM и COM является утилита emitcom, создающая COM–обёртки для классов SOM на языке C++. emitcom входил в состав SOM 3.0 Beta (февраль 1996), но в состав SOM 3.0 Release (декабрь 1996), как и многие другие возможности, не вошёл.

Следует, однако, отметить, что поскольку COM никак не решает проблему хрупкого базового класса, следует относиться с осторожностью к подобным мостам. Обёртки COM, производимые emitcom, соответствуют слепку интерфейса класса в момент создания, и при изменениях в интерфейсе нужно создавать новые версии обёрток с новыми GUID COM–интерфейсов, которые бы, тем не менее, поддерживали COM–интерфейсы старых версий обёрток. Интерфейсы COM, создаваемые утилитой ctypelib для классов SOM, помеченных модификатором ODdual, не следует использовать из компилируемых языков программирования, поскольку низкоуровневое представление такого интерфейса не стабильно. ctypelib обычно перезаписывает библиотеку типов COM, а поддержание параллельно нескольких разных версий интерфейса не предусмотрено.

Direct-to-SOM (D2SOM, DTS)[править | править вики-текст]

При использовании эмиттеров в компилируемых языках программирования, таких, как C++, эмиттер C++ производит видимость того, что SOM класс является C++ классом. somInit проецируется на стандартный конструктор, а somAssign — на operator=. Однако, при реализации своих классов основную роль играет написание .idl, а реализация методов не выглядит как реализация методов класса. Необходимо постоянно вызывать компилятор SOM для обновления файлов. SOM получается чем–то инородным для языков программирования, компиляторы которых не имеют встроенную поддержку SOM.

Компилятор Direct-to-SOM C++ позволяет обойтись без написания .idl файлов. .idl файлы генерируются на основе заголовочных файлов DTS C++, а не наоборот. Таким образом, компилятор DTS C++ предоставляет полноценную однородную среду разработки, позволяющую писать всё на одном языке. Работать с som.dll в DTS C++ подобно тому, как работать с objc.dll в Objective-C.

Эмиттеры по–прежнему нужны, но только для импорта сторонних библиотек. В Microsoft C++ есть возможность писать #import <something.tlb>. Аналогично можно было бы поступить с IDL в DTS C++, но этого реализовано не было. Вместо этого нужно применить эмиттер, который создаст .hh файлы, требуемые для компилятора DTS C++. Компилятор DTS C++ поддерживает как обычные C++ классы, так и SOM классы, наследуемые от SOMObject (явно или неявно, при #pragma SOMAsDefault (on)). Как и в другом гибриде, Objective-C++, возможность смешивать классы из разных иерархий ограничена.

Direct-to-SOM C++ появился в MetaWare High C++ и позже продублирован в VisualAge C++, причём, эти реализации несовместимы напрямую, только через импорт/экспорт в .idl. В книге «Putting Metaclasses to Work» был описан ещё один, третий известный диалект DTS C++, компилятора для которого ещё не существует.

Альтернативные реализации[править | править вики-текст]

Существует открытая реализация SOM - somFree[12]. Проект заявляет двоичную совместимость с оригинальной реализацией от IBM. Netlabs.org поддерживает реализацию NOM, которая основана на принципах SOM, но не является совместимой ни на уровне исходного кода, ни на двоичном уровне.

Примечания[править | править вики-текст]

Ссылки[править | править вики-текст]