Дата публикации: Dec 07, 2012 10:55:46 AM
Продуманные, проверенные временем языки имеют определенный присущий им набор правил или соглашений, в своем роде стиль - как решаются или решены те или иные задачи. Это философия языка. Один язык категорически запрещает все, что опасно - это один подход. Другой разрешает все - это другая философия. Один ограничен минимумом символов для переносимости, другой использует все, что есть на клавиатуре. Один различает регистр символов, другой - нет. Это тоже философский вопрос!
Здесь я опишу элементы философии Фортрана, как я ее понимаю. Возможно, удастся осветить темные места. Если есть идеи, дополнения или возражения, прошу высказаться!
В Фортране принята концепция связи по вложенности вложенных областей видимости. Простыми словами это означает, что имена, определенные в области видимости видны во вложенной области видимости, если в последней не определены свои объекты с теми же именами. Например, процедура может иметь внутренние процедуры (отделенные от тела словом contains) - они имеют доступ к объектам самой процедуры. То же в модуле - модульные процедуры "видят" все объекты модуля. Аналогично в основной программе - относительно внутренних процедур и блоков BLOCK. С другой стороны, различные процедуры закрыты друг от друга, даже если они в одном модуле.
Какие следствия из этого? Модульная технология подразумевает именно это: процедуры модуля читают и меняют данные модули и вызывают друг друга, а извне скрытые (private) процедуры и данные не видны. А вот что касается внутренних процедур, то это может быть неожиданно и даже привести к ошибкам. В Паскале и С такое (поправьте меня, если я ошибусь) невозможно. Зато в Perl сходная идеология. Оговорка насчет экранирования во многом снимает проблему, хотя не до конца. Если в программе есть переменная J, хранящая значение функционала, скажем, а во внутренней процедуре объявлена переменная j для использования в цикле, то и J, и j означают (в процедуре) именно счетчик цикла, а функционал в любом случае не пострадает. Однако, если переменная-счетчик не объявлена, а сразу используется (это называется неявная типизация, о ней мы отдельно поговорим), то беда - значение J из программы будет утрачено. Аналогично с функциями: можно определить массив sin, записать туда грехи и работать с ними - но функция синус будет недоступна. Какая польза от этого? Можно реализовать свой алгоритм расчета синуса, например.
Проблема касается только скаляров: остальные объекты надо объявлять, так или иначе. Впрочем, если во вложенной области определяется массив, к примеру, а в объемлющей области есть одноименный массив той же конфигурации, проблема остается. Можно потребовать (от себя) объявлять все объекты, указав директиву IMPLICIT NONE, которая запрещает неявную типизацию. Только надо следить: если забыл объявить переменную, а ошибка не возникает - значит, выше есть такое имя и используется объект из объемлющей области.
Еще один путь защититься - это использование стерильных (PURE) процедур. Они не могут менять ничего за пределами своего тела, что гарантирует целостность объектов в объемлющей области видимости. Читать они могут, но вряд ли, все-таки, это приведет к проблеме: если значение нужно, значит, оно там откуда-то есть, а если объект предполагался локальным, то откуда же его значение?
Однако стерильные процедуры не могут ничего делать за своими пределами, в том числе осуществлять ввод и вывод, что не всегда приемлемо.
Ну, хватит придираться. Запретите неявную иипизацию и следите за тем, чтобы все объявлялось - и проблем не будет. Но все же, какая польза от такого подхода к видимости объектов? В модулях, как уже отмечалось, это естественно. То, что блок (конструкция, допускающая локальные объявления данных в теле программы) видит то, что его окружает - тоже естественно. Неожиданно это для внутренних процедур, особенно в основной программе. Надо оно или это излишне? Зависит ведь от точки зрения. Если функция просто вычисляет некоторое выражение, то видимость может вызвать проблемы: например, если промежуточный результат записать в какую-нибудь TEMP, которая совпадет с одноименной переменной вовне. А бывает так, что нужно многократно проводить какие-то операции над данными программы - тогда удобно поручить это внутренней процедуре, которая видит все - просто операторы, которые это делали в основной программе, перенести в процедуру, без возни с параметрами и потери скорости на их передачу.