В этом вопросе язык для надёжного программирования ближе всего к Оберону, но с более жёсткими условиями по недопущению перекрытия.
Все используемые идентификаторы кроме предопределённых должны быть предварительно объявлены. Имя, использованное для объявления на уровне модуля или функции, должно быть уникальным в одной области видимости, за исключением предварительного объявления функции, что нужно для возможности косвенной рекурсии. Имя объявления, сделанного внутри функции также должно быть уникальным во всей функции, в том числе и для не пересекающихся областей видимости внутри неё.
Объявление-d, сделанное на уровне модуля-m доступно по имени от начала его появления в тексте до конца m. В других модулях-am d доступно только в том случае, если оно было помечено как экспортируемое в m, и только в тех из них, где m был импортирован. Доступ к d в am осуществляется через импортированное имя m - im, следующей за ним разделяющей точкой и именем d
module m { const(c = d + 1; // ошибка - d ещё не объявлена +d = 0; // пометка объявления "+" как экспортированное e = d + 1) proc p() { const(f = d; e = 6) // ошибка - е уже объявлено в этой области уровнем выше ... } } module am { import(im = m) // переименовываем, m недоступна для использования const(d = im.d; e = m.d; // ошибка, модуль m был переименован для использования f = im.e) // ошибка, объявление е не было экспортировано в m proc p() { { const (a = 3) ... } { const (a = 0.6)// ошибка - хотя a=0.6 объявлена в другой области ... // видимости, но в пределах одной процедуры, } // что запрещено } }Имя объявления, сделанного на уровне структуры должно быть уникальным лишь в пределах самой структуры. Имя может совпадать как с предопределёнными именами, так и с именами, объявленными на уровне модуля, функций и других структур, в том числе вложенных, так как из-за строго иерархического обращения к элементам структуры не может быть никакого кофликта имён.
module a { const (b = 1) var (r struct { r struct { r, b int } } ) proc p() { r.r.r = 0; r.r.b = 1 } }
В языке нет разновидности импорта, позволяющей включать экспортированные объявления других модулей в область видимость импортирующего модуля так, как будто они являются его собственными. Это сомнительное удобство вносит неразбириху относительно принадлежности используемых сущностей и создаёт возможность для появления ошибок в результате манипуляций с импортом и расширения интерфейса используемых модулей.
Из заданных ограничений следует, что имена объявлений, сделанные внутри функции могут совпадать с именами объявлений, сделанных в других функциях. Также, имя внутри функции может совпадать с именем одной из функций, объявленных ниже по тексту. Это послабление нужно для возможности создания однопроходного транслятора.module a { const(+a = 10)// обращение к собственному модулю не предусмотрено, // поэтому имя объявления может совпадать с именем модуля. proc +b() { const(c = a; d = 4)// d объявлена ниже, поэтому не входит в текущую ... // область видимости } proc +d() { // область видимости d = 4 закончилась внутри b() const(c = a + 1)// хотя с уже встречается в b(), но так как области // b() и d() не пересекаются, то объявление корректно. ... } }Запрет на перекрытие имён и возможность иметь несколько конкретизаций синтаксисов создают трудности, требующие разрешения:
- Невозможность использования подходящего имени, если оно уже занято предопределённым идентификатором, что может быть неприятным, если их будет много.
- Невозможность использования объявления с именем, совпадающим с ключевым словом, от модуля, написанного под другой синтаксис.
module @const { // @ как в C# const (+@module = 1) }
Я рассматриваю и другую возможность - отказ от ключевых слов и ограниченное число предопределённых имён. При необходимости добавления новых в обновлённой версии языка, они добавляются в псевдомодуль, чтобы исключить пересечение с именами в модуле, написанном ранее. Но это решение пока кажется сложней и проблематичней. Вариант, в котором наоборот - все ключевые слова и предопределённые идентификаторы помечены, кажется мне слишком неудобным и уродливым.
@module m { @const (c = 1) @type (t @int) @var (v t) @func f(i t) (res @bool) { res = i < @max(t) / 2 } }