Вот здесь и проявились недостатки Оберона, касающиеся строк и символов. Кое-что уже обсуждалось на нашем форуме в теме
Ответ Alone Coder'у, но было известно и ранее (
http://maxandreev.narod.ru/oberon/CritiqueOberonLanguage_RUS.pdf).
Символ - это всегда одиночный символ, понятие "длина" (в том смысле как "длина строки") к нему неприменимо. Если мы хотим работать с цепочкой символов фиксированного размера, то к нашим услугам массивы (обычные, т.е. фиксированной длины, не открытые). А вот если последовательность символов может иметь переменную длину, то требуется особый тип "строка".
И это, вообще-то, три разных структуры данных. В чём-то они похожи, поэтому можно в некоторых случаях установить соответствие (скажем "символ" - "ARRAY 1 OF CHAR" - "строковая константа длины 1"), но есть и отличия, которые не позволяют говорить, что это одно и то же.
Строка - это реализация абстракции "последовательность символов переменной длины". Раз длина переменная, значит как-то нужно хранить текущую длину. Для этого существуют два основных механизма - хранить текущую длину в какой-то служебной ячейке (Pascal strings или c-addr u Форта) или помещать после последнего символа какой-то терминатор (обычно символ с кодом 0 - "нуль-терминированная строка").
Но тот или другой механизм - это именно механизм, позволяющий нам работать с символами. s[0] ТурбоПаскаля или 0X ББ в большинстве случаев от нас скрыт, потому что функционирует автоматически. Мы сталкиваемся с этим, когда либо утыкаемся в ограничения, либо работаем не с самими символами, а именно с механизмом. Например, могут возникнуть затруднения, если в ТП нам нужны строки длинней 255 символов, или если среди символов обрабатываемой строки в КП должен быть 0Х.
Также, если мы пишем процедуру для выделения в памяти буфера для строки или для передачи строки в какую-то внешнюю библиотеку (биндинг), то уже сами переходим с уровня "абстрактная последовательность символов" на уровень механизма. И тогда s[0] или завершающий символ становятся важны, потому что они становятся не скрытыми служебными, а тоже обрабатываемыми (пользовательскими). И приходится буфер выделять на 1 символ больше или вставлять завершающий 0Х и пр.
Вот и при задании константного ARRAY OF CHAR через строковые константы имеет значение, для чего именно мы вводим этот константный массив, т.е. на каком уровне мы работаем. Если нам важны только сами символы в кавычках, то автоматически добавляемый 0Х - это "лишний" символ (накладные расходы, плата за возможность задавать символы в кавычках).
Код: "OBERON"
TYPE Labirint = ARRAY 3 OF ARRAY 16 OF CHAR;
CONST Map = Labirint("...o..##...oo12", "...o..##...oo35", "...o..##...oo78");
Если здесь задан лабиринт 3х15, то 16-й столбец явно лишний. Он необходим лишь потому, что кавычки автоматически добавляют 0Х, который нужно куда-то девать. Другое дело, если нам требуется в программе ограничитель из нулевых символов по какой-то причине, тогда автоматическое добавление уместно.
Кстати, а как вставить символ 0Х слева? 0Х+"..000..12" не срабатывает.А вот если массив у нас только буфер для нуль-терминированных строк, которые мы собираемся куда-то передавать, то значит мы работаем с 0Х как с полноправным символом, предполагаем его наличие и должны быть предупреждены, если в массиве для него не хватило места. Пример из предыдущего сообщения
Код: "OBERON"
TYPE MsgStr= ARRAY 3,7 OF CHAR;
CONST Way = MsgStr("Hello!" , "Error" , "Try" );
Поэтому предлагаю, чтобы сам программист указывал, для чего именно он хочет использовать этот константный массив - это "массив из символов фиксированного размера", где значение имеют только явно указанные символы в кавычках, или же это буфер для нультерминированных строк, где служебный завершитель тоже важен.
Указывать это можно, например, так
Код: "OBERON"
TYPE Labirint = ARRAY 3 OF ARRAY 15 OF CHAR;
CONST Map = Labirint$("...o..##...oo12", "...o..##...oo35", "...o..##...oo78");
В этом случае кавычки не генерируют лишний 0Х, в массив попадают только те символы, что указаны явно внутри кавычек и их должно быть ровно столько, какова длина массива по последнему измерению. Символ $ употребляется только при задании константного массива из CHAR или BYTE и влияет только на то, как следует понимать строковые константы в кавычках.
А если $ не употреблять, то предлагаю не только добавлять 0Х, но и разрешить указывать в кавычках меньше символов (недостающие заполняются нулями). Если 0Х не влезет в массив, то выдавать ошибку.
В любом случае можно использовать перечисление символов в скобках ("H","e", "l", "l","o","!",0X). И тогда в массив попадут лишь эти символы, и их должно быть указано ровно столько, какова размерность массива. И никто не будет требовать, чтобы последним символом был нулевой.
Вот только не знаю, удачно ли такое обозначение (я выбрал $, потому что в КП s$ означает "символы, находящиеся в массиве s").