[recovery mode] Особенности и отличия языка программирования MSH от MUMPS
Основой для языка MSH послужил язык MUMPS. MUMPS разработан где то в 80-х годах прошлого столетия, как впрочем и многие другие современные языки. Он с самого начала разрабатывался как язык для создания больших информационных систем, работы с большими распределенными данными. В связи с чем имеет некоторую специфику. Программирование на этом языке несколько отличается от программирования на других языках. Несмотря на его малую распространенность у него существует довольно устойчивое сообщество в разных частях света программистов разрабатывающих на нем информационные системы. За время своего существования MUMPS мало изменился. Некоторые элементы языка потеряли актуальность. И язык на данный момент несколько архаичен. Хотелось бы иметь более современный язык подобный MUMPS. С этой целью и создавался язык MSH. Некоторые концепции языка MSH отличаются или отсутствуют в языке MUMPS. В основном для аудитории MUMS программистов и написан данный материал, но может и другим будет интересно.
В MUMPS константы отсутствуют. В MSH они введены. Но из-за специфики языка существовать в виде неизменяемых переменных времени исполнения программы они не могут. Поэтому в MSH они введены как объекты времени компиляции. Что то типа define языка Си в самом упрощенном виде. В момент трансляции языка MSH в Pi код виртуальной машины все константы в исходном тексте заменяются их значениями. То есть в Pi коде их уже нет. Константы могут использоваться как значения переменных, в качестве индекса или имени переменной. Формат команды: Constant nameConst=valConst; Справа от знака равенства может находиться только константа, выражение не допускается. Имя константы должно быть уникальным и с именами переменных не пересекаться.
В MUMPS переменные хранятся в деревянной структуре, будь то глобали или локали. Правда у глобалей в MUMPS есть небольшое отличие — сокращенный синтаксис. В MSH нет сокращенного синтаксиса. Хранение данных в виде только дерева позволяет унифицировать обращение к данным. Можно писать программы обработки любого дерева данных. Но в программах часто приходится работать с различными промежуточными значениями и хранить их в дереве не эффективно. Доступ к дереву всегда влечет дополнительные расходы, как бы мы этот доступ не оптимизировали. В MSH данные могут храниться как в деревянной структуре, так и в одномерном массиве. В одномерном массиве лучше хранить промежуточные данные, хотя можно хранить и любые данные. Доступ к массиву значительно быстрее, чем к дереву. Дерево хранить так называемые разряженные данные. То есть в дереве хранятся только существующие вершины. Например имеем дерево [1] [5] [78]. Только эти вершины и будут хранится в дереве. Массив хранит все промежуточные значения. Например мы создали 78 элемент в массиве $78. Будут созданы все элементы в этом массиве вплоть до 78. Если мы создаем дерево, то создается и пустой массив и наоборот, если создается массив, то создается и пустое дерево. Но это конечно относится к текущей реализации MSH.Видимость переменных в MUMPS имеет свои особенности. То что в MUMPS называют глобалями в других языках это обращение к базам данных. А вот локали являются аналогом переменных в других языках. Ну с глобалями все ясно. Это внешние данные и они доступны как из любого задания данного приложения, так и из других приложений. Хранятся они в виде файлов и как правило несколько глобалей в одном файле. В MSH в общем то все так же за исключением одного момента. Каждая глобаль хранится в отдельном файле. А если точнее то в нескольких файлах одного каталога. Этот момент существенен с технологической точки зрения построения информационной системы. И еще одно замечание. Глобали в MSH синхронизированы по обращению. Это значит, что к ним можно обращаться одновременно из разных заданий без дополнительной синхронизации. Теперь детальней разберемся с локалями. В общем случае локаль в MUMPS является глобальной переменной верхнего уровня в смысле языка Си. Аналога переменным из кучи в языке Си, в MUMPS нет. А вот аналог автоматическим переменным языка Си есть. Это локали перечисленные (или не перечисленные), в зависимости от формы команды, в команде New. Область видимости таких локалей от команды New до команды завершения блок Quit. Оригинальное конечно решение обусловленное природой MUMPS и отсутствием в нем деклараций переменных. По моему мнению глобальная область видимости локалей по умолчанию спорное решение, хотя и не фатальное. В MUMPS где я в основном работаю напрямую с глобалями, локальных переменных не так уж много и конфликты имен не часты, хотя и случаются. Но все же это не удобно при программировании. В MSH принят другой подход. Команды New здесь нет. А локализация переменных выполнена по префиксу. Переменные имеющие префикс % локализованы внутри задания. Переменные имеющие префикс ^tmp локализованы внутри приложения. Переменные не имеющие этих префиксов локализованы внутри блока Do. Это касается одинаково как деревьев, так и массивов.
В MUMPS объектов нет. Но ООП получило повсеместное распространение. Основная масса современных языков программирования так или иначе поддерживает ООП. MSH не исключение. Для того чтобы было ООП язык должен иметь для начала объекты. В общем случае описание объект состоит из декларативной части и части реализации. MSH не поддерживает декларации переменных, значит декларативной части описания объектов не будет. Существует описание объекта в MSH в виде части реализации. В MUMPS код программы представлен в виде программных модулей. Точки входа в модуле являются подпрограммами и функциями. Программный модуль в MSH и взят в качестве описания объекта (класса). Метки модуля являются точками входа этого модуля. Точки входа в этом случае являются публичными свойствами get этого класса. Публичными свойствами set этого класса будут та же точка входа как и get модифицированная определенным символом. В качестве такового в MSH выбран символ точка ».». У свойства в MSH кроме доступа get и set есть еще операция Kill -удаление свойства. В этом случае имя свойств модифицируется префиксом »…». Наследование классов в MSH является множественным и реализовано с помощью команды Extend. Классы перечисленные в этой команде в порядке следования являются предками данного класса. Во время выполнения программы при обращении к свойству объекта его описание сначала ищется в исходном модуле затем в модулях перечисленных в команде Extent в порядке их следования. Более раннее положение модуля в команде дает ему больший приоритет. Защищенные свойства реализуются с помощью системного свойства %this. Объекты в MSH могут находиться только в дереве. В массиве могут храниться только примитивные типы данных.Методы класса так же являются точками входа в модуле класса. Создаются объекты с помощью стандартного свойства %new.Например имеем класс Person со свойством Age. В модуле класса есть точки входа «Age» и ».Age».В переменной [1,2] создадим объект.Set [1,2].%new= Person; Обращение к свойству Age объекта Person по записи.Set [1,2].Age=50; Обращение к свойству Age объекта Person по чтению.Set $1=[1,2].Age; Эти команды транслятор преобразует в обращения к подрограммам. Но это не единственный способ обращения к свойствам. По записи к свойсту Age можно обратиться и через метод.Do [1,2].Age (50); В MSH модуль выполняет двоякую роль. Кроме модуля класса он может трактоваться и как модуль программ. В этом случае к точкам входа обращаются как к подпрограммам. Предположим в модуле Person есть метка ABC. Тогда к ней можно обратиться как к программе. Правда в этом случае переменная %this будет пустой.Do Person.ABC (125, D,25.6); Так можно организовать классовые методы.
Еще одной эффективной парадигмой программирования являются события. Как правило языки программирования не содержат средств обработки событий. Они обычно вынесены в стандартные библиотеки. В MUMPS обработка событий в зачаточном состоянии и сводится к обработке ошибок. В MSH события включены в язык. События могут быть как системными, порожденными системой. Так и пользовательскими, порожденными пользователем с помощью команды EventTrap. Аргументы этой команды передаются обработчикам этого события.Команда EventCall назначает событию программу обработчик. В момент возникновения события текущее задание будет прервано и будет выполнена программа обработчик в новом блоке Do. Как будто в этом месте встретилась команда Do с вызовом данного обработчика. Это значит что локальные переменные выполнявшейся программы в обработчике события будут недоступны.Команда EventWait останавливает выполнение текущей программы и ожидает возникновение события. При возникновении события текущая программа продолжает работу и с этого момента в программе становятся доступными переданные аргументы. Новый блок Do не создается и поэтому все локальные переменные этого блока Do доступны после каоманды EventWait.Если событие возникло до появления команд EventCall и EventWait. То событие будет обработано первой встретившейся командой EventCall или EventWait. После обработки событие удаляется. Команда EventDelete удаляет событие вместе с обработчиками.