Коллеги, в нашем языке массивы определяются так:
Language Report писал(а):
An array is a structure consisting of a number of elements which are all of the same type, called the element type. The number of elements of an array is called its length. The elements of the array are designated by indices, which are integers between 0 and the length minus 1.
т.е. ограничений на размер массивов не накладывается напрямую; косвенно - максимальное целое, представимое в языке - MAX(LONGINT).
Но процедура LEN Определяется вот так:
Language Report писал(а):
LEN(v, x)
Argument type: v: array; x: integer constant
Result type: INTEGER
Function: length of v in dimension x (first dimension = 0)
LEN(v)
Argument type: array type
Result type: INTEGER equivalent to LEN(v, 0)
Argument type: String
Result type: INTEGER
Function: length of string (not counting 0X)
Таким образом, LEN может работать только с массивами <MAX(INTEGER).
На базе и386 не было практического смысла ставить этот вопрос. Но на базе амд64 - нужно прояснить. Ведь вполне можно вообразить на практике массив с >MAX(INTEGER) байт. И уж тем более - для системных целей POINTER [untagged] TO ARRAY OF BYTE, который можно использовать чтобы хоть ко всему адресному пространству обращаться.
Что же делать с LEN?
Вариант А: переопределить, что она возвращает LONGINT. Слабость этого варианта:
VAR len: INTEGER;
len := LEN(a); (* Ошибка: требуется явное приведение типов *)
Ну, можно потребовать, чтобы все пользовались приведением:
len := SHORT(LEN(a));
Но это неудобно в подавляющем большинстве употреблений. И кроме того, потребует правки прежних программ при переносе на амд64.
Вариант Б: пусть возвращает INTEGER для фиксированных массивов малого размера, и LONGINT для открытых массивов и для больших фиксированных. Слабость - открытые массивы часто используются в параметрах:
PROCEDURE P (IN a: ARRAY OF BYTE);
VAR len: INTEGER;
len := LEN(a) (* Ошибка, даже если фактический параметр - малый фиксированный массив *)
Вариант В: пусть возвращает INTEGER, но дополнить определение: если значение выходит за ОДЗ INTEGER, происходит аварийный останов. (Это эквивалентно тому, чтобы LEN возвращала LONGINT, но компилятор вместо LEN() везде вставлял SHORT(LEN()) с принудительной проверкой ОДЗ.) Такой вариант удобен для подавляющего большинства употреблений; и не потребует правки прежних программ при переносе на амд64.
Но как тогда узнавать длину больших массивов?
1) ввести LONGLEN? Плюс этого варианта - все чисто, нет "особых случаев" (см. п. 3). Минус - новое имя в Сообщении о языке.
2) ввести SYSTEM.LEN?
3) использовать LONG(LEN())?
VAR long: LONGINT;
long := LONG(LEN(a))
В этом примере кажется неуместной явная запись LONG(), поскольку и так подразумевается неявное приведение INTEGER к LONGINT даже при
long := LEN(a)
А вот в таком - вполне уместна:
long := LONG(LEN(a)) - 1;
Поскольку в
long := LEN(a) - 1;
в вычитании участвуют два INTEGER, и должна проводиться проверка ОДЗ.
Минус этого варианта - введение особого случая: обычно LEN возвращает INTEGER, но иногда, если "снаружи" оказалось LONGINT - то возвращает LONGINT.
Есть, конечно, и
Вариант Г: ограничить длину массива числом MAX(INTEGER).
Какие есть соображения или предложения по теме, коллеги?