Когда-то, еще в 90-ых годах, вынуждено перейдя с Delphi на FoxPro 2.6 (работает в консоле под DOS), в связи необходимостью по работе переписывать большой чужой проект для компании, я решил сделать FoxPro 2.6 объектно ориентированным. Для того, чтоб реализовать псевдообъектно ориентированность я использовал массивы строк, в которых записывал методы в виде строки. Это выглядело примерно так Массив[4] = "myfunc()", а при вызове данного метода так &Массив[4]. Теперь, занявшись языком OneScript, я понял, что могу повторить этот фокус. Как потом оказалось, повторение получилось более успешным, так как мой метод создания объектов в OneScript позволяет делать приватные свойства и приватные методы. К тому же, созданный налету программно, объект единожды проходит процедуру компиляции перед загрузкой, что, по сравнению с интерпретатором FoxPro, ускоряет выполнение кода. FoxPro каждый раз производит интерпретацию кода для выполнения.
Для реализации объектно ориентированнности я использую функцию "ЗагрузитьСценарий()", но перед этим программно формирую файл сценария. Если в этом сценарии пишу "Перем Моя экспорт", то это общедоступная переменная, а если тоже самое пишу без слова "экспорт", то приватная. Если в сценарий вставляю строку
Функция Мояфункция() экспорт Возврат 2*2; КонецФункции
, то это общедоступная функция, а если без слова "экспорт", то приватная. Создание файла, для которого я придумал расширение "osm", так как это внешний модуль и его подключение через функцию "ЗагрузитьСценарий", я реализовал в одной функции, которую назвал "СоздатьООПОбъект" (см.библиотеку UfaScript). Все это заработало, но кроме этого надо реализовать механизм наследования объектов, желательно реализовать особую функцию "конструктор", в которой можно инициализировать переменные объекта.
Для реализации конструктора достаточно в короткой функции "СоздатьООПОбъект" реализовать автозапуск функции с ключевым именем "конструктор". А для наследования пришлось сначала написать спец функцию "СоздатьНаследникаООПОбъекта", но так как список описания переменных и функций для объекта я реализовывал в виде строкового массива, то понял, что удобнее производить сборку итогового массива из двух при реализации механизма наследования, а массивы с перечнем переменных и функций называть образами объекта. Потому от функции "СоздатьНаследникаООПОбъекта" я отказался, заменив ее функцией "СоздатьООПОбъектИзМассива", благодаря которой я могу создать массив для объекта из цепочек массивов родителей.
Я реализовал, чтоб базовые переменные "ИмяОбъекта" - строковое имя объекта, "Родитель" - строковое имя родителя объекта, "UfaScript" - указатель на библиотеку "UfaScript", "НашОбъект" - указатель на созданный объект, вставлялись автоматически при использовании функции "СоздатьООПОбъект". Затем создал образ объекта "ОбразОбъектБазовый", в котором еще предопределил переменные "Экран" - указатель на экран, куда вставляется объект (экран - это указать на обычный массив с объектами, которые надо изобразить на экране), "Индекс" - указатель на порядковый номер объекта в массиве Экран, "ТипОбъекта" - просто номер типа, чтоб определять возможности объекта. Затем начал создавать образы нужных объектов в виде функций, заполняющих массивы строк родительскими переменными и методами, а так же добавляющими строки с переменными и методами текущего объекта. При создании нового итогового массива для объекта таким слиянием массивов, я произвожу сортировку, чтоб записи с ключевым словом "Перем " были вначале.
Но этого механизма недостаточно, так как нужно еще обеспечить переопределение методов в объектах потомках. Для реализации всех возможностей нужного мне переопределения, я понял, что достаточно двух управляющих команд: "#Удалить" и "#Переименовать". Первая удаляет ненужный метод у родителя, а вторая переименовывает метод. Теперь у программиста появилась возможность удалить любой метод в массиве родителя и затем, если надо, определить новый метод с таким же именем. Так же благодаря возможности переименовать любой метод, можно в любом месте тела функции нового метода вызывать старый переименованный метод родителя.
Все вышесказанное позволяет создавать полноценные объекты на OneScript и заявить, что теперь OneScript является объектно ориентированным языком программирования.
Дополнительно, в качестве бонуса, для тех кто дочитал до конца данную статью, я расскажу, как я реализовал механизм передачи функции в качестве параметра в OneScript. Механизм передачи функции в виде параметра реализован двуми короткими функциями: ВызватьФункцию(Функ,Где)", где параметр "функ" - это строка с текстом вызова функции, а параметр "где" - это указатель на модуль, в котором располагается вызываемая функция, "ВыполнитьКодИзМассива" - которая исполняет созданный код и возвращает результат выполнения через метод "Результат". В итоге передача функции в качестве параметра будет выглядеть так:
Сообщить("12) "+U.ВызватьФункцию("Итог(7)",ЭтотОбъект).Результат());
Как видно, из текста в функцию можно передавать любые параметры, но, возможно, придется писать так:
Сообщить("12) "+U.ВызватьФункцию("Итог("+Парам+")",ЭтотОбъект).Результат());
Потому что вызов данной функции будет происходить во внешнем модуле, созданном программно. А можно так:
Сообщить("12) "+U.ВызватьФункцию("Итог(ТотОбъект.Парам)",ЭтотОбъект).Результат());