Насколько же всё-таки уродлив стандартный обероновский FOR!
Особенно по сравнению с остальным изяществом, присущим Оберон-технологиям. Или это не сам язык виноват, а только реализация BlackBox?
Я про принцип «В цикле
FOR n:= A TO B BY Step выражения
A,B и
Step должны иметь тот же тип ,что и переменная
n » (хотя вроде бы явно это нигде не описано, но в BlackBox именно так).
Я согласен насчет
А и
B - это значения, которые может принимать
n, поэтому требование однотипности вполне естественно. А вот шаг - другое дело, по самому своему смыслу шаг это не значение, это
разница значений - смещение от одного элемента к другому. Почему разница (протяженность) насильно совмещена с самим элементом (точечной отметкой)? Потому что это числа? Но эти числа представляют сущности разной природы!
Так в кинотеатре в данном ряду есть кресло №3, которое имеет сиденье, спинку, ножки и подлокотники, на кресле можно сидеть и смотреть фильм. И есть в данном ряду разница (смещение) между креслами. Вот у разницы ни ножек, ни спинок, ни сидений нет (подлокотников, конечно, тоже) и сидеть на этой разнице нельзя, пусть даже для 10-го и 13-го кресел она тоже равна 3.
Хуже того, константное выражение после BY определяет не только (абсолютную) величину смещения на каждой итерации, но и направление в котором идет цикл. Получается, что, строго следуя этому правилу, мы не сможем организовать перебор беззнаковых чисел в нисходящем порядке, потому, что не сможем написать
FOR n:=255 TO 0 BY -1, ведь (-1) вне диапазона 0..255!
В Паскале таких проблем не было, потому что у цикла FOR было только 2 возможных шага - «+1» и «-1». Или вернее так — был только единичный шаг, но он мог или прибавляться (с контролем правой границы) или вычитаться (с контролем левой). И никого не смущало (даже никто и не задумывался), что в байте нет отрицательных чисел, а шаг (-1) есть. Ведь и для беззнаковых чисел есть декремент и операция вычитания. В диапазоне 0..255 нет отрицательных чисел, но вычесть из одного байта другой мы можем (и даже остаться в том же диапазоне, если вычитаем из большего меньшее).
А вот,оказывается, нельзя вычитать, в Обероне только прибавлять можно (n:=n + Step). И если у нас в диапазоне значений есть отрицательные — хорошо, можно это отрицательное прибавить и тем самым «вычесть». А если диапазон с нуля-извините...
«— Извинить не могу!» (М.Булгаков Мастер и Маргарита). Даже для знаковых типов это слишком ...Ну ладно, опять скажу «уродливо», вместо слов за которые я, как честный модератор, должен был бы сам себя отлучить.
Почему в положительном направлении мы можем двигаться с шагом от 1 до 127, а в отрицательном от 1 до 128? Набор смещений по элементам должен определяться
количеством этих элементов, а не их
значением.
Я не призываю вводить в цикл FOR Оберона специальные слова для обозначения направления (хотя, по-моему, это было бы гораздо красивее и нагляднее), но диапазон возможных шагов после BY должен быть иным!
Итак, пусть в цикле
FOR n:= A TO B BY Step компилятор вычислит константное выражение
Step, используя свой самый большой диапазон целых чисел. Знак Step определяет направление цикла: «+» - возрастание , «-» - убывание, нулевой шаг недопустим. А вот абсолютную величину шага нужно сравнить с мощностью (количеством значений) типа переменной
n. Если
ABS(Step) >MAX(T)-MIN(T), то мы заведомо не можем шагнуть без вылета из цикла (цикл вообще не выполнится ни разу или выполнится 1 раз для
n=A). А тогда зачем вообще этот цикл? Думаю, тут компилятор должен сразу схватить программиста за руку и сообщить, что с шагом или с типом переменной что-то не так. А вот если шаг (по абсолютной величине) принадлежит диапазону
1..MAX(T)-MIN(T), то цикл FOR транслируется как обычно, с соблюдением всех вышеизложенных оптимизаций.
Кстати, надо пересмотреть вышеизложенное, с учетом условия
1<=ABS(Step) <=MAX(T)-MIN(T). Не перескочит ли какой-нибудь шаг из этого диапазона «забор» Nlast или «контрольно-следовую полосу» (B-Step), что мы возвели для предотвращения переполнений? Учесть нужно как знаковые так и безнаковые типы.