Модули и пакеты
В NewLang реализована концепция программных модулей и пакетов - которая повторяет идею иерархического расположения файлов в каталогах файловой системы, примерно так же, как это сделано в языке Python, но разделителем имен выступает не точка, а символ “\” (как разделитель каталогов в Windows).
Имя модуля может содержать только строчные английские буквы или цифры. Данное ограничение связано с прямым отображением имен модулей на объекты в файловой системе, так как у разных файловых систем могут быть различные возможности с поддержкой кодировок и разные требования к преобразованию регистров символов.
Под модулем в NewLang понимается файл исходным кодом (с расширением *.src). Модули предназначены для того, чтобы в них хранить часто используемые функции, классы, константы и т.п. Их можно условно разделить на модули и программы: программы предназначены для непосредственного запуска, а модули для импортирования их в другие программы, но функционально модули и программы ничем между собой не отличаются.
Объекты модуля
Все объекты, определенные внутри одного модуля без указания глобального простанства имен, видны только в рамках текущего файла.
Время жизни статической и локальной переменных модуля одинаковые, и ограничены временм жизни самого модуля, но статическая и локальная переменные модуля отличаются с точки зрения многопоточности.
Статическая переменная модуля всегда будет в единственном экземпляре для всех потоков, тогда как локальная переменная модуля будет для каждого потока своя (аналог thread_local (C++11)).
Как импортировать модули?
Относительное имя программного модуля начинается на символ “\”, и в этом случае расположение файла программного модуля указывается относительно текущего файла.
Абсолютное имя программного модуля начинается на два символа “\\” и указывает на файл модуля относительно каталога текущего исполняемого файла (или в списке каталогов для поиска программных модулей, который можно переопределить, например, с помощью аргументов командной строки).
Полное имя текущего модуля (файла) содержится в переменной препроцессора ‘@\\’.
Самый простой способ импортировать модуль, это записать его имя со скобками как при вызове функции. Причем в скобках можно передать аргументы для инициализации модуля, список импортируемых функций и т.д.
Так как NewLang разрабатывается как компилируемый язык, то загрузка модулей возможна как статически, так и динамически (очень похоже на статическую и динамическую ликновку с dll библиотеками).
- \dir\module() - статическая загрузка модуля по относительному пути
- \\root\dir\module() - статическая загрузка модуля по абсолютному пути
- \\("каталог\файл") - динамическая загрузка модуля во время выполнения программы
При динамической линковке, компиляция исходного кода модуля и все проверки будут выполнятся только во время выполнения приложения, тогда как статическая загрузка модуля позволяет выявить возможные ошибки еще на этапе компиляции программы.
По умолчанию, при статической линковке модуля, импортируются все его макросы, функции и переменные модуля, тогда как при динамической загрузке моуля, макросы не импортируются. ?????????????????????????????????????????????????????????????
Что такое пакет в NewLang?
Пакет в NewLang – это имя каталога, который включает в себя другие каталоги и модули и при этом содержит дополнительный файл __init__.src.
Пакеты используются как дополнение к пространству имен, что позволяет работать с модулями через указание уровня вложенности (через символ \). Но в отличии от Python и Java, где модули и пакеты заменяют собой пространство имен (namespace), в NewLang модульная структура и области имен используются одновременно и при указании полного имени объекта, программные модули и пространства имен можно объединять.
Например, полное имя переменой можно записать с указанием программного модуля \root\dir\module::ns::name::var
,
где root и dir это каталоги в файловой системе относительно текущего моделя, а module — имя файла, т.е. root/dir/module.src
Для импортирования пакетов используется тот же синтаксис, что и для работы с модулями.
Использование пакетов
Рассмотрим следующую структуру пакета:
fincalc
|-- __init__.src
|-- simper.src
|-- compper.src
|-- annuity.src
Пакет fincalc содержит в себе модули для работы с простыми процентами (simper.src), сложными процентами (compper.src) и аннуитетами (annuity.src). Файл __init__.src в отличии от Python, не может быть пустым, а должен в явном виде содержать команды загрузки модулей, входящих в пакет
Например для нашего случая содержимое __init__.src может быть вот таким:
\simper();
\compper();
\annuity();
Для использования функции fp из модуля для работы с простыми процентами, можно использовать один из следующих вариантов (для сравнения приведен аналогичный код на Python, когда это возможно):
Импорт одного модуля без указания псевдонима:
Python:
import fincalc.simper
fv = fincalc.simper.fv(pv, i, n)
NewLang:
\fincalc\simper();
fv := \fincalc\simper::fv(pv, i, n);
С указанием псевдонима имени модуля:
Python:
import fincalc.simper as sp
fv = sp.fv(pv, i, n)
NewLang:
sp := \fincalc\simper();
fv := sp.fv(pv, i, n);
Импорт одной конкретной функции:
Python:
from fincalc import fv
result = fv(pv, i, n)
NewLang:
\fincalc\simper(__import__="fv");
result := fv(pv, i, n);
Импорт всего пакета:
NewLang:
\fincalc();
result := fv(pv, i, n);