Эмуляция объектной технологии в не ОО-средах
Fortran
FORTRAN должен фактически устранить кодирование и отладку.
FORTRAN: Предварительный отчет, IBM, Ноябрь, 1954
Самый старый уцелевший язык программирования Fortran по-прежнему широко используется в сфере научных вычислений. Это может показаться удивительным для тех, кто использует такие "структурированные" языки как Pascal, но в Fortran легче достигнуть многих ОО-свойств, благодаря возможностям, которые считаются низкоуровневыми и предназначены для других целей.
Немного контекста
Язык Fortran был первоначально создан как инструмент для программирования на IBM 704 командой IBM во главе с Джоном Бэкусом (позже он принимал активное участие в описании языка Algol). Первая версия языка появилась в 1957 году. Затем последовал Fortran II, введший подпрограммы. Fortran IV появился в 1966 году и был стандартизирован ANSI (Fortran III не получил широкого распространения). Дальнейший процесс развития привел к Fortran 77, одобренному в 1978 году, имевшему лучшие управляющие структуры и приятные упрощения. После длительного процесса пересмотра появился Fortran 90 и Fortran 95, они были по-разному приняты и до сих пор не заменили своих предшественников.
Для большинства специалистов в компьютерных науках Fortran устарел. Однако можно найти немало программистов Fortran еще с тех времен и тех, в чьих дипломах стоит "физик-теоретик", "прикладной математик", "инженер-механик", или даже "специалист по ценным бумагам", использующих Fortran повседневно и не только в старых проектах, но и в новых разработках.
Постороннему наблюдателю иногда кажется, что программирование в физике и других научных дисциплинах, где позиции Fortran наиболее сильны, остается в стороне от программной инженерии. Это отчасти верно, отчасти - нет. Низкий уровень языка и особая природа научного вычисления (ПО создаются людьми, хотя и учеными по образованию, но часто не имеющими формального программного образования) приводят изначально к невысокому качеству создаваемого ПО. Но некоторые из лучших и самых мощных программных систем созданы именно в этой области, включающей и передовое моделирование чрезвычайно сложных процессов, и поразительные инструменты научной визуализации. Такие продукты больше не ограничиваются изящными, но небольшими числовыми алгоритмами. Как и их аналоги в других областях приложения, они часто манипулируют сложными структурами данных, опираются на технологию баз данных, включают множество компонентов пользовательских интерфейсов. И, хотя это может показаться удивительным, они все еще зачастую пишутся на языке Fortran.
Техника COMMON
Fortran система состоит из главной программы и ряда подпрограмм. Как обеспечить схожесть с абстракцией данных?
Возможная техника состоит в том, чтобы представить данные в так называемом общем блоке COMMON, а экспортируемые компоненты (например, put и т. д. для стеков) реализовать в виде независимых подпрограмм. Блок COMMON - это механизм Fortran, предоставляющий доступ к данным любой подпрограмме, желающей их получить. Вот набросок подпрограммы put для стека действительных чисел:
SUBROUTINE RPUT (X) REAL X C C ВТАЛКИВАНИЕ X НА ВЕРШИНУ СТЕКА C COMMON /STREP/ TOP, STACK (2000) INTEGER TOP REAL STACK C TOP = TOP + 1 STACK (TOP) = X RETURN END
Эта версия не управляет переполнением (будет исправлено в следующей версии). Функция, возвращающая элемент вершины:
INTEGER FUNCTION RITEM C C ВОЗВРАЩЕНИЕ ВЕРШИНЫ СТЕКА C COMMON /STREP/ TOP, STACK (2000) INTEGER TOP REAL STACK RITEM = STACK (TOP) RETURN END
Здесь также необходимо было бы проверять стек на пустоту. Подпрограммы REMOVE и другие строятся по тому же образцу. Имя общего блока - STREP - объединяет различные подпрограммы, дающие доступ к одним и тем же данным.
Ограничения очевидны: данная реализация описывает один абстрактный объект (один отдельный стек), а не абстрактный тип данных, из которого во время выполнения можно создать множество экземпляров. Мир Fortran статичен: необходимо указывать размеры всех массивов (в примере 2000 - произвольно выбранное число). Поскольку отсутствует универсальность, то в принципе, придется объявлять новый набор подпрограмм для каждого типа элементов стека. Отсюда имена RPUT и RITEM, где R означает Real. Можно справиться с этими проблемами, но не без значительных усилий.
Техника подпрограммы с множественным входом
Техника, основанная на блоке COMMON, как это видно, нарушает Принцип Лингвистических Модульных Единиц. В модульной структуре системы подпрограммы, являясь концептуально связаннами, физически независимы.
Эту ситуацию можно улучшить (не убирая другие перечисленные ограничения) посредством особенности языка, легализованной в Fortran 77 - множественными точками входа в одной подпрограмме.
Это расширение, введенное, возможно, для других целей, можно использовать во благо ОО-подхода. Клиентские подпрограммы могут вызывать точки входа, как если бы они были автономными подпрограммами, и разные входы могут иметь разные аргументы. Вызов входа начинает выполнение подпрограммы с этой точки. Все входы разделяют хранимые данные подпрограммы, появляющиеся с директивой SAVE и сохраняемые от одной активизации подпрограммы к другой. Понятно, куда мы клоним: эту технику можно использовать для определения модуля, инкапсулирующего абстрактный объект, почти как в инкапсулирующем языке. Здесь модуль моделируется подпрограммой, структура данных - набором объявлений с директивой SAVE, и каждый компонент соответствующего класса в ОО-языке - входом, заканчивающимся инструкцией RETURN:
ENTRY (arguments) ... Инструкции ... RETURN
В отличие от предыдущего решения, основанного на COMMON, теперь все необходимое сосредоточено в единой синтаксической единице. В таблице 34.1 дан пример реализации стека действительных величин. Вызовы клиента выглядят следующим образом:
LOGICAL OK REAL X C OK = MAKE () OK = PUT (4.5) OK = PUT (-7.88) X = ITEM () OK = REMOVE () IF (EMPTY ()) A = B
Взглянув на этот текст, можно почти поверить, что это использование класса, или, по крайней мере, объекта, через его абстрактный, официально определенный интерфейс!
Этот стиль программирования может успешно применяться для эмуляции инкапсуляции Ada или Modula-2 в контекстах, где нет другого выбора, кроме использования Fortran. Конечно, он страдает от жестких ограничений:
- Не разрешаются никакие внутренние вызовы: в то время как подпрограммы в ОО-классе обычно опираются друг на друга для реализации, вызов входа той же подпрограммы будет понят как рекурсия - проклятие для Fortran - и бедствие во время выполнения во многих реализациях.
- Как отмечалось, этот механизм строго статичен, поддерживая только один абстрактный объект. Он может быть обобщен преобразованием каждой переменной в одномерный массив. Но не существует переносимой поддержки для создания динамического объекта.
- На практике некоторые среды Fortran не слишком хорошо работают с множественными входами подпрограмм.
- Наконец, сама идея использования языкового механизма для целей, отличных от проектируемых, порождает опасность путаницы.