OberonCore
https://forum.oberoncore.ru/

Почему убрали перечисления.
https://forum.oberoncore.ru/viewtopic.php?f=29&t=122
Страница 1 из 4

Автор:  Алексей Елин [ Четверг, 02 Март, 2006 16:48 ]
Заголовок сообщения:  Почему убрали перечисления.

Меня давно интересует вопрос, на который я не могу найти подробного ответа: почему убрали перечисления из оберона?
Сам Вирт в своей лекции в России сказал по этому поводу примерно так: с ними (перечислениями) были какие то проблемы, я не помню точно какие, и мы решили их убрать.

Единственное объяснение которое я знаю: они мешают расширять типы (нельзя добавлять новые перечисления). Но на самом деле эта проблема решается, а в Zonnon перечисления были вновь добавлены (как и многое другое :?).

Что по этому поводу знает многоуважаемый All?

Автор:  Сергей Губанов [ Четверг, 02 Март, 2006 18:35 ]
Заголовок сообщения:  Re: Почему убрали перечисления.

Алексей Елин писал(а):
Сам Вирт...

...писал, что (статья "От Модулы к Оберону"):
Цитата:
Тип перечисление слишком простое средство, чтобы выйти из-под контроля. Однако, оно не позволяет распространять расширяемость за пределы модуля. И либо нужно ввести средство для расширения типа перечисление, либо же от типа перечисление надобно отказаться. Причина, по которой мы выбрали второй путь — путь радикального решения — кроется в том, что во все возрастающем числе программ непродуманное использование перечислений (и диапазонов) ведет к демографическому взрыву среди типов, что, в свою очередь, ведет не к ясности программ, а к ее многословию. В связи с использованием экспорта и импорта перечисления приводят к исключению из правил, и согласно ему импорт идентификатора типа также приводит к автоматическому импорту всех связанных с типом идентификаторов констант. Это исключение нарушает концептуальную простоту и создает для реализаторов языка неприятные проблемы.

Короче, использование обычных констант есть слишком простое средство чтобы программист смог запутаться, поэтому вводить перечисления просто незачем. То есть перечисления следовало бы ввести если бы программисты (часто) путались с обычными константами. Но программисты (обычно) не путаются с обычными константами, поэтому вводить перечисления причины нет.

Алексей Елин писал(а):
Но на самом деле эта проблема решается

Не решается.
Вот был модуль:
Код:
DEFINITION Colors;
  CONST red = 1; green = 2
END Colors.

Потом мы его заменили на такой:
Код:
DEFINITION Colors;
  CONST red = 1; green = 2; blue = 3
END Colors.

(добавили еще одну константу не изменив старые). Этот новый модуль заменяем со старым модулем. Никакие старые программы перекомпилировать не надо. Но, если бы мы добавили еще одну константу в тип-перечисление, то мы бы изменили этот тип. Отныне, это был бы уже совсем другой тип. Все старые модули, которые использовали старый тип не захотели бы работать с новым типом (абсолютно все сто тыщь мильёнов старых модулей надо было бы перекомпилировать).

Автор:  GameHunter [ Среда, 23 Май, 2007 11:58 ]
Заголовок сообщения: 

По сравнению с Модулой-2 (например), где перечисления есть, в Обероне, как мне кажется, усложняется индексация массивов.

Автор:  Александр Ильин [ Среда, 23 Май, 2007 12:19 ]
Заголовок сообщения: 

GameHunter писал(а):
По сравнению с Модулой-2 (например), где перечисления есть, в Обероне, как мне кажется, усложняется индексация массивов.

Неплохо бы пример под такое заявление. А то что-то не понятно, что может быть проще, чем индексация всегда с нуля и всегда до LEN()-1.

Автор:  GameHunter [ Среда, 23 Май, 2007 13:42 ]
Заголовок сообщения: 

Перечисление подразумевает не только множество констант, но и свои границы. Таким образом, чтобы в Обероне организовать перечисление, нужно не только по одной константе на каждый элемент перечисления, но и одну или две дополнительные константы для границ. Только в этом случае добавление новых элементов в перечисление не приведёт к изменению индексации массивов. Однако, за границами в Обероне надо следить вручную, что не удобно и потенциально может привести к ошибке.

Модула-2:
Код:
DEFINITION Colors;
  TYPE
    Color=(Red,Green,Blue);
    ColorProperty=ARRAY [Color] of ...
END Colors

...

FOR c:=MIN(Colors.Color) TO MAX(Colors.Color) DO
...
    prop[c]:=...
...
END;


Оберон:
Код:
MODULE Colors;
  CONST
    Red*=0;
    Green*=1;
    Blue*=2;
    MaxColor*=Blue;
  TYPE
    ColorProperty=ARRAY MaxColor+1 of ...
END Colors

...

FOR c:=0 TO Colors.MaxColor DO
...
    prop[c]:=...
...
END;

Автор:  GameHunter [ Среда, 23 Май, 2007 13:43 ]
Заголовок сообщения: 

О, пардон, про LEN()-1 не заметил :oops: . Вопрос снимается.

Автор:  GameHunter [ Среда, 23 Май, 2007 13:49 ]
Заголовок сообщения: 

Хотя, при объявлении типа массив неудобство всё-таки сохраняется.

Автор:  Александр Ильин [ Среда, 23 Май, 2007 14:43 ]
Заголовок сообщения: 

GameHunter писал(а):
Хотя, при объявлении типа массив неудобство всё-таки сохраняется.

Да, неудобство есть. Есть и другие неудобства, например, следующая процедура возвращает номер дня недели, соответствующий указанной дате:
Код:
PROCEDURE DayOfWeek* (IN d: Date): INTEGER;

Если возвращаемое значение = 0, то это понедельник (как у нас) или воскресенье (как у них)? Надо сравнивать с константой Monday либо Sunday. Вопрос: где объявлены нужные константы? В этом же модуле? Не обязательно. Надо искать, рыть документацию. Это во-первых.

А во-вторых, никто не помешает этот результат сравнить с любой другой целочисленной константой, например, Sundae (десерт такой). Представьте, что мы пишем программу, которая помогает составить меню для ресторанчика на неделю, и возможные блюда мы объявили в виде констант. Как видите, опечатка не так уж невозможна, а компилятор промолчит, спокойно сравнивая десерт с днем недели.

Чтобы избежать подобных ошибок можно делать объектные обертки для перечислимых типов, я где-то на этом форуме приводил пример реализации. Это будет несколько непривычно, но работать будет, читабельность повысит и от ошибок - застрахует.

Кстати, в компиляторе XDS поддерживаются перечислимые типы, причем в обероновских исходниках. Там динамической загрузки нет, перечислимые типы контролировать гораздо проще. Да, там при изменении перечислимого типа производится перекомпиляция всех зависимых модулей, но там это не проблема.

Автор:  Борис Рюмшин [ Среда, 23 Май, 2007 14:55 ]
Заголовок сообщения: 

Похоже всё-таки нужно нам делать FAQ... э-э-э... Wiki :)

Автор:  GameHunter [ Среда, 23 Май, 2007 19:52 ]
Заголовок сообщения: 

Цитата:
Чтобы избежать подобных ошибок можно делать объектные обертки для перечислимых типов, я где-то на этом форуме приводил пример реализации. Это будет несколько непривычно, но работать будет, читабельность повысит и от ошибок - застрахует.


Пример поискал, не нашёл. Приведите, пожалуйста, более конкретную ссылку.

Цитата:
Кстати, в компиляторе XDS поддерживаются перечислимые типы, причем в обероновских исходниках.


Да. Но, к сожалению, связанные с перечислениями множества там в оберон не прикрутили :(

Автор:  Александр Ильин [ Среда, 23 Май, 2007 21:43 ]
Заголовок сообщения: 

GameHunter писал(а):
Пример поискал, не нашёл. Приведите, пожалуйста, более конкретную ссылку.

Посмотрел, это было в закрытой части форума. Скопирую сюда, пусть будет достоянием общественности. Пример реализации типа "день недели" для модуля Dates.

Код:
MODULE Dates;

TYPE
  DayOfWeek* = POINTER TO LIMITED RECORD
    index-: INTEGER
  END;

  VAR
    monday-, tuesday-, wednesday-, thursday-, friday-, saturday-, sunday-: DayOfWeek;
    daysOfWeek: ARRAY 7 OF DayOfWeek;

  PROCEDURE GetDayOfWeek* (IN d: Date): DayOfWeek;
    (** Берем дату и определяем день недели *)
  BEGIN
    IF ... THEN RETURN monday
    ELSIF ... THEN RETURN tuesday
    ...
    END
  END GetDayOfWeek;

  PROCEDURE IndexToDayOfWeek* (index: INTEGER): DayOfWeek;
    (** Возвращаем день недели с указанным номером *)
  BEGIN
    RETURN daysOfWeek[index]
  END IndexToDayOfWeek;

<...>

  PROCEDURE NewStdDOW (index: INTEGER; OUT dow: DayOfWeek);
    (** Создаем день недели и связываем с индексом *)
  BEGIN
    NEW(dow);
    dow.index := index;
    daysOfWeek[index] := dow
  END NewStdDOW;

BEGIN
  NewStdDOW(0, monday);
  NewStdDOW(1, tuesday);
  NewStdDOW(2, wednesday);
  NewStdDOW(3, thursday);
  NewStdDOW(4, friday);
  NewStdDOW(5, saturday);
  NewStdDOW(6, sunday);
END Dates.


Что имеем в результате? Переменные monday..sunday экспортированы только для чтения и инициализированы при запуске, т.е. для клиентов являются константами. Тип DayOfWeek (LIMITED) не является расширяемым, и экземпляры объектов этого типа за переделами модуля Dates создать невозможно, значит полный контроль над предметной областью у нас есть, а число "предметов" равно числу созданных "констант".

Что может клиентский код? Передавать константы в качестве параметров и получать их в качестве выходного значения с полной статической и динамической проверкой типов. Сравнивать значение переменной с константами (равно или не равно). Благодаря необязательному, но в данном случае реализованному, полю index (экспорт только для чтения) может задаваться отношение порядка, то есть, можно проверять переменную относительно константы на больше-меньше.

Одновременно с этим модуль Dates может безболезненно дополнить список констант, что не потребует перекомпиляции клиентского кода. Если нужно по индексу дня недели быстро найти нужную константу типа DayOfWeek, можно использовать процедуру IndexToDayOfWeek. Массив daysOfWeek не экспортирован, чтобы избежать перекомпиляции клиентов при увеличении его размера.

По сути дела, получается, что у нас те же самые целочисленные константы, но в объектной обертке, гарантирующей правильный тип.

Читабельность: процедура GetDayOfWeek однозначно может быть сопоставлена с LIMITED-типом и read-only переменными, что дает узнаваемый паттерн реализации перечисления.

Все это плод моей фантазии, с удовольствием выслушаю критику и замечания. Илья Ермаков что-то говорил по поводу отсутствия литералов и дженериков, но я его не понял, а он не пояснил.

PS: В языках Oberon и Oberon-2 такое реализовать с достаточной степенью уверенности невозможно по причине отсутствия LIMITED-типов.

GameHunter писал(а):
Да. Но, к сожалению, связанные с перечислениями множества там в оберон не прикрутили :(

О, вы знакомы с XDS? Практически или теоретически? Что-то разрабатывали на нем?

Автор:  Info21 [ Четверг, 24 Май, 2007 00:28 ]
Заголовок сообщения: 

Александр Ильин писал(а):

Код:
MODULE Dates;

TYPE
  DayOfWeek* = POINTER TO LIMITED RECORD
    index-: INTEGER
  END;
  StdDayOfWeek = POINTER TO RECORD (DayOfWeek)
  END;



Возможно, вместо LIMITED имелось в виду ABSTRACT? А то непонятно, зачем тогда расширять тип-то.

Автор:  Александр Ильин [ Четверг, 24 Май, 2007 06:31 ]
Заголовок сообщения: 

info21 писал(а):
Возможно, вместо LIMITED имелось в виду ABSTRACT? А то непонятно, зачем тогда расширять тип-то.

Ой, вы правы. Не доглядел. Дело в том, что в первоначальном варианте было ABSTRACT, а когда сюда переносил решил сделать LIMITED. Поправил пост наверху.

Дело в том, что абстрактные записи допускают расширение и создание расширенных экземпляров, а у меня задача стояла не допустить появление несанкционированных объектов этого типа. Клиент не может создавать новые дни недели, поскольку процедуры модуля Dates, куда они попадут в качестве параметров, не будут знать, что с ними делать.

Автор:  Сергей Оборотов [ Четверг, 24 Май, 2007 08:05 ]
Заголовок сообщения: 

Неплохо. Но лучше, всё-таки, если такой механизм (после стандартизации) появится в языке.

Автор:  Евгений Темиргалеев [ Четверг, 24 Май, 2007 09:32 ]
Заголовок сообщения: 

Гм, какой механизм? какая стандартизация?
Я могу ошибаться, но:
1) стандарт - это сообщение о языке. Он уже есть и меняться не будет. На то это и стандарт.
2) Если Вы имеете в виду появление перечислений, то их тоже, поверьте, убрали не просто так. Это нужно для большей независимости между модулями-компонентами. Перечисление - тип. Чем больше зависимостей от типов, тем больше модулей нужно перекомпилировать, если тип поменялся (Вы добавили или убрали одно значение из перечисления).

Автор:  Сергей Оборотов [ Четверг, 24 Май, 2007 09:50 ]
Заголовок сообщения: 

Евгений Темиргалеев писал(а):
Гм, какой механизм? какая стандартизация?
Механизм был указан чуть выше. Как уже было сказано Александром, при изменении значений "перечисления" DayOfWeek его тип остается прежним. Со всеми вытекающими отсюда последствиями.

Автор:  Евгений Темиргалеев [ Четверг, 24 Май, 2007 10:12 ]
Заголовок сообщения: 

Перечисления в таком виде... мне кажется что такое решение не будет подходящим для всех задач. А средства языка - средства универсальные... Я сразу даже не предположил, что Вы предлагаете именно такую реализацию вставить в язык. :)

Автор:  Wlad [ Четверг, 24 Май, 2007 10:27 ]
Заголовок сообщения: 

Александр Ильин писал(а):
Посмотрел, это было в закрытой части форума. Скопирую сюда, пусть будет достоянием общественности.

С этого места - поподробней, пожалста! :о)

Автор:  Сергей Оборотов [ Четверг, 24 Май, 2007 10:40 ]
Заголовок сообщения: 

Евгений Темиргалеев писал(а):
Я сразу даже не предположил, что Вы предлагаете именно такую реализацию вставить в язык. :)
Если Вы помните, я не предлагал вставить в язык именно такую реализацию. Лишь только обладающую указанными Александром свойствами. И то после разбора всех альтернатив ( читай стандартизации ). А в каких случаях она не подойдет?

Автор:  Александр Ильин [ Четверг, 24 Май, 2007 10:52 ]
Заголовок сообщения: 

Евгений Темиргалеев писал(а):
Перечисления в таком виде... мне кажется что такое решение не будет подходящим для всех задач. А средства языка - средства универсальные... Я сразу даже не предположил, что Вы предлагаете именно такую реализацию вставить в язык. :)

Безусловно, не для всякой задачи. Например, таким способом удобно задавать небольшие перечисления, но не диапазоны типа TYPE Int = 0..32768. А если нет диапазона, то и массив ARRAY Int OF ... тоже создать не получится.

Еще таким способом не удастся задать субтип для контроля физической величины, чтобы не сложить ненароком скорость с высотой. В этом случае лучше сделать объектные обертки ценой потери простоты записи (придется использовать height.Add(height2) место INC(height, height2)).

Я за концептуальную чистоту Оберона: если что-то можно реализовать уже имеющимися средствами, не нужно вводить новых "для удобства". Пусть лучше в голове будет порядок. Есть в этом какая-то своя... романтика, что ли.

Страница 1 из 4 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/