Оберон-клуб «ВЄДАsoft»

Твердыня модульных языков
Текущее время: 28 мар 2024, 11:26

Часовой пояс: UTC + 2 часа




Начать новую тему Ответить на тему  [ Сообщений: 5 ] 
Автор Сообщение
СообщениеДобавлено: 13 июн 2019, 21:38 
Не в сети
Администратор
Аватара пользователя

Сообщения: 273
Откуда: Россия
Я уже писал, какие , по моему мнению, нужно наложить ограничения на управляющую переменную (счетчик) цикла FOR.
Для удобства скопирую сюда:
Saferoll писал(а):
Еще бы наложить ограничения на переменную. Я не так радикален, чтобы как в Аде создавать переменную прямо в заголовке цикла. Но лучше бы сделать ее "как можно более локальной":
1) после FOR должен быть простой идентификатор, без всяких селекторов и квалификаторов (не элемент массива, записи или другого модуля).
2) переменная цикла FOR должна быть локальной переменной "самой локальной" процедуры, т.е. должна быть описана в разделе VAR (не в параметрах!) той процедуры, непосредственно в теле которой находится FOR
3) в блоке инициализации модуля (или в блоке финализации) может быть употреблена переменная цикла, которая описана в разделе VAR этого модуля, и эта переменная не должна быть экспортируемой.
Вот таким на мой взгляд должен быть FOR в Обероне. Собственно, всё это кроме ограничения на переменную цикла уже реализовано.

Поясню, почему считаю такие ограничения необходимыми. Переменная цикла должна изменяться только при помощи скрытого механизма, поэтому она не должна испытывать воздействия откуда-то извне. Она имеет такой же смысл, как индекс внутри оператора сумма (сигма большое) или переменная в кванторе, поэтому она "связанная переменная" - имеет смысл только внутри.
Будучи студентом, а потом и преподавателем, я наблюдал частые ошибки с оператором for в Паскале. Очень часто вызывали какую-то процедуру содержащую цикл FOR изнутри тела цикла FOR, но оба цикла использовали одну и ту же глобальную переменную в качестве счетчика. В результате значение переменной менялось весьма замысловато, и такие ошибки было трудно отследить. Причем во вложенных циклах на одном уровне такие ошибки возникали редко и легко обнаруживались, потому что заголовки в тексте располагались рядом.
Ошибки возникали потому, что в любом цикле студенты "по математической привычке" использовали индексы i,j,k или n и m, или x,y,z (смотря для какой предметной области составляли программу). Создавая подпрограмму, они в соответствии с принципом "разделяй и властвуй" не задумывались, откуда эта подпрограмма может быть вызвана и не будет ли конфликта переменных. Собственно для этого структурное (модульное) программирование и предназначено. Вот только ленились для счетчика цикла употреблять локальную переменную, а использовали для всех циклов for глобальные.
Я ввел строгое (такое же строгое, как запрет goto) правило "Использовать в циклах for для счетчика только "самую локальную" переменную". Ошибок стало меньше. Возражения об экономии памяти в стеке и таблицах компилятора отметались доводами:
1) структурность и наглядность в учебных программах важнее,
2) учебные программы далеко не достигали предела имеющихся ресурсов
3) а если достигали, экономия пары-тройки переменных для счетчиков мало что давала.
Наиболее хитрые "экономисты памяти" предлагали циклы вроде for n:=1 to n do , где n-формальный параметр процедуры, передаваемый по значению (например, размер обрабатываемого в цикле массива). Это я тоже запретил из-за малой наглядности, что вскоре стало понятно и самим "ревнителям экономии", стоило им только заняться задачей, где требовалась размерность массива на каждой итерации.
Мой опыт убеждает, что лучше всего использовать в качестве переменной цикла FOR локальную переменную, причем самую локальную, какую возможно. Доводов против, кроме сомнительной "крохоборской" экономии и возможности применять неструктурные хакерские трюки, я не знаю. Разве что, "нестандартность" и "усложнение компилятора".
Но стандарт я ругаю уж который год, к тому же в некоторых языках наименьшая локальность переменной цикла - как раз стандарт. Например, в Аде (как уже упоминалось). Кстати, в С++ тоже можно задать счетчик цикла, локальный только в самом этом цикле:
Код: "C"
for(int i=1;i<N;i++)...

А усложнение компилятора настолько незначительное, что тоже доводом не является.

_________________
А кроме того, я думаю, что корFORген должен быть разрушен!


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 13 июн 2019, 21:48 
Не в сети
Администратор
Аватара пользователя

Сообщения: 273
Откуда: Россия
Итак, что же потребуется для ограничения локальности переменной цикла FOR? Совсем немного - чуть изменим процедуру ForImproved в модуле OPP:
Код: "OBERON"
  1. PROCEDURE ForImproved; (* Concept and implementation by Oleg Komlev *)
  2. PROCEDURE varFor(id:OPT.Object):BOOLEAN;
  3. BEGIN
  4. RETURN (id.mode=Var)&(id.vis=0) &(id.mnolev=level);
  5. END varFor;
  6. BEGIN (* построение синтаксического дерева для FOR *)
  7. OPS.Get(sym); (* взять символ после FOR *)
  8. IF sym = ident THEN qualident(id); (* если это идентификатор, уточнить его *)
  9. IF (id^.typ^.form IN intSet) & varFor(id) THEN (* он должен быть целого типа и нужной локальности *)
  10. ...

Новая функция varFor проверяет, является ли эта переменная простой переменной из раздела VAR, что у ней нет модификаторов и что она определена на том же уровне, где употребляется. Основные условия я проверил - глобальные, экспортируемые, переменные-параметры вызывают ошибку. Необходимо, конечно, более тщательно протестировать это нововведение, может быть что-то я упустил.
Что не совсем хорошо, так это не совсем внятное сообщение об ошибке: "68.control variable must be integer". Среди стандартных сообщений я более подходящего не нашел, потребуется сформулировать новое.

_________________
А кроме того, я думаю, что корFORген должен быть разрушен!


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 13 июн 2019, 22:44 
Не в сети
Аватара пользователя

Сообщения: 1019
Откуда: Днепропетровская обл.
Отличное предложение, Олежек. Внедрил. Только проверка на локальность идёт отдельным условием. Добавил новый код ошибки #91 "control variable must be local".

Напоминаю, что "правильный" FOR в Ofront+ можно включить для любого Оберон-диалекта ключиком -f (а в режиме -3 он уже активен).


Вложения:
Ofront+.png
Ofront+.png [ 54.8 КБ | Просмотров: 5222 ]
Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 14 июн 2019, 10:22 
Не в сети
Администратор
Аватара пользователя

Сообщения: 273
Откуда: Россия
2Zorko. Спасибо за оперативное внедрение. Согласен со введением нового кода ошибки.

_________________
А кроме того, я думаю, что корFORген должен быть разрушен!


Вернуться к началу
 Профиль  
Ответить с цитатой  
СообщениеДобавлено: 17 июн 2019, 22:03 
Не в сети
Администратор
Аватара пользователя

Сообщения: 273
Откуда: Россия
На форуме Oberoncore обсуждается вопрос "Следует ли сделать переменную цикла FOR еще более локальной (ограничить локальность телом цикла)". Тогда будет больше похоже на FOR в Аде, что по смыслу цикла FOR - хорошо.
Технически это сделать можно, ведь создается же там временная скрытая переменная для граничного значения, почему бы не создать и видимую? Но, понятно, что реализация будет сложнее - надо вводить отдельную область видимости именно для тела цикла. Независимо от технической возможности, возникает вопрос "а верно ли это по духу Оберона"? Однако "дух"- понятие не формализуемое, поэтому каждый понимает (и имеет право понимать!) это по-своему.
Конечно, счетчик цикла по смыслу является связанной переменной внутри тела цикла, поэтому самая правильная область его локализации - тело цикла. Это довод ЗА.
Против - слишком большие отступления от привычных областей видимости. Со скрытой переменной таких проблем нет именно потому, что она скрытая! А тут получается, что кроме кроме блока процедур есть отдельные области еще и внутри тела процедуры (тело цикла FOR).
То, что я ранее предлагал в реализации "правильного FOR", касалось семантики и механизма реализации, от синтаксиса и "основных принципов" отступлений не было (принципы "не менять переменную и не использовать ее значение после цикла" - нормальные "структурные" принципы, аналогичные паскалевским). Требование для счетчика быть локальным в пределах процедуры не затрагивает сами области видимости.
А вот появление счетчика в заголовке FOR и пропадание его после цикла кажутся мне уж слишком большим "переломом традиций".
Может быть, конечно, на мое мнение подсознательно влияет и лень в поиске механизма реализации "локальнофоровой" переменной ;) , но я думаю, лучше ограничиться локальностью на уровне процедуры, как это сейчас сделано. Это некий компромисс между самой широкой локальностью (отсутствие требований локальности вообще) и "самой правильной по смыслу цикла FOR локальностью" (локальность ограничена телом цикла).
Цикл FOR в Аде имеет свои плюсы, но с точки зрения "величины изменений основных принципов" минусы перевешивают. Аде - адово, Оберону - обероново.


Кстати, в Паскале-подобном языке Modula-2 Revision 2010 цикл FOR по своим свойствам похож на аналогичный оператор в Аде:
1) Заголовок цикла является описанием переменной цикла, она существует пока цикл выполняется, но исчезает по окончании цикла.
2) Переменную цикла нельзя менять в теле цикла, она меняется автоматически - так, как задано в заголовке.
По синтаксису в простейшем варианте тоже выглядит похоже на Аду
Код: "OBERON"
  1. FOR n IN [1..10] OF INTEGER DO
  2. ...
  3. END

но полный синтаксис FOR в Модуле-2 (rev.2010) сложнее (и, на мой взгляд, излишне наворочен и усложнен).

_________________
А кроме того, я думаю, что корFORген должен быть разрушен!


Вернуться к началу
 Профиль  
Ответить с цитатой  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 5 ] 

Часовой пояс: UTC + 2 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
© VEDAsoft Oberon Club