Oberon space
General Category => Общий раздел => Тема начата: valexey_u от Сентябрь 04, 2013, 11:21:23 am
-
В Oberon-report'e этот момент не уточнен (и вообще никак не описан), поэтому предлагаю обсудить, уточнить и договориться.
Итак, ситуация следующая - модуль A экспортирует указатель на структурный тип A.R, но сам A.R не экспортирует. Может ли модуль B импортирующий A.R создать в куче переменную типа A.R?
Код:
MODULE A;
TYPE
R = RECORD END;
P* = POINTER TO R;
END A.
MODULE B;
IMPORT A;
VAR
p : A.P;
BEGIN
NEW(p)
END B.
Технически мы это можем без проблем. Но в некоторых реализациях такое вот может быть не возможно, кроме того, если такое разрешить, то по сути мы лишаемся возможности создавать opaque-типы простым способом. Кроме того возникает логическое противоречие - почему то локальную переменную мы завести не можем, а переменную через NEW уже можем.
Поэтому предлагаю следующее:
1) Если импортирован только указательный тип, то с указателем можно делать все что обычно, но нельзя NEW. То есть новых экземпляров типа R пользователь заводить не может нигде.
2) Если импортирован еще и сам структурный тип (record or array), то создавать экземпляры (через NEW или иначе) можно, а доступ есть к тем полям которые экспортированны (помечены звездочкой), можно КОПИРОВАТЬ экземпляры (statement ":="). При этом конечно возможна ситуация когда тип экспортирован, но ни одного поля не экпортированно. Увы :-)
Ну и наконец есть особый случай, который тоже неоднозначен, и про который в репорте нет ничего:
MODULE A;
TYPE
P* = POINTER TO RECORD foo* : INTEGER END;
END A.
MODULE B;
IMPORT A;
VAR
p : A.P;
BEGIN
NEW(p); (* это можно? *)
p.foo := 42 (* а это? *)
END B.
Экспортирован тип-указатель на анонимную запись, причем у этой записи есть экспортированные поля. Таким образом переменную типа этой самой записи пользователь создать не может. Но, очевидно, он может обратиться к полю. Но может ли он создать через NEW новый экземпляр таковой безымянной записи?
Предлагаю создание экземпляра через NEW, в этом случае, также запретить. Таким образом у нас получается возможность создавать типы переменные которых могут создаваться ТОЛЬКО через фабрики (где они будут гарантированно инициализированны корректно), но при этом остается возможность прямого обращения к некоторым полям. (кроме того, опять таки, это логично, что если я не могу создать локальную переменную, то и через NEW тоже не могу её создать).
Как-то так. Какие будут мнения?
-
В Oberon-report'e этот момент не уточнен (и вообще никак не описан), поэтому предлагаю обсудить, уточнить и договориться.
Итак, ситуация следующая - модуль A экспортирует указатель на структурный тип A.R, но сам A.R не экспортирует. Может ли модуль B импортирующий A.R создать в куче переменную типа A.R?
Не могу согласиться с этим утверждением:
4. Declarations and scope rules
...
The scope rule has the following amendments:
1. If a type T is defined as POINTER TO T1 (see 6.4), the identifier T1 can be declared textually following the declaration of T, but it must lie within the same scope.
Как видно, тут написано, что тип, на который указывает указательный тип, должен быть видимым в той области видимости, где находится сам этот указательный тип.
Экспорт какой-либо сущности -- это по сути расширение области видимости этой сущности на другие модули (через квалифицированный импорт), а значит, экспортироваться должен не только тип, указывающий на запись/массив, но и сами эти запись/массив...
-
Поля записи, отмеченные знаком экспорта, должны быть доступны через экспортированный тип указателя на эту запись, независимо от того, экспортирован тип записи или нет, именован или нет.
-
В Oberon-report'e этот момент не уточнен (и вообще никак не описан), поэтому предлагаю обсудить, уточнить и договориться.
Итак, ситуация следующая - модуль A экспортирует указатель на структурный тип A.R, но сам A.R не экспортирует. Может ли модуль B импортирующий A.R создать в куче переменную типа A.R?
Не могу согласиться с этим утверждением:
4. Declarations and scope rules
...
The scope rule has the following amendments:
1. If a type T is defined as POINTER TO T1 (see 6.4), the identifier T1 can be declared textually following the declaration of T, but it must lie within the same scope.
Как видно, тут написано, что тип, на который указывает указательный тип, должен быть видимым в той области видимости, где находится сам этот указательный тип.
Тут говорится о валидности объявлений (declaration, процесса объявления новых типо), я же говорю и спрашиваю о экспорте и импорте. То есть не про объявления, это разные понятия.
-
Ну и наконец есть особый случай, который тоже неоднозначен, и про который в репорте нет ничего:
MODULE A;
TYPE
P* = POINTER TO RECORD foo* : INTEGER END;
END A.
А вот, похоже, экспортировать указатели на анонимные записи вряд ли можно.
Но тогда, по аналогии, нельзя экспортировать и указатели на процедуры?
-
Тут говорится о валидности объявлений (declaration, процесса объявления новых типо), я же говорю и спрашиваю о экспорте и импорте. То есть не про объявления, это разные понятия.
В оберонах модификатор экспорта -- это часть декларации. Так в чём проблема-то?
-
Ну и наконец есть особый случай, который тоже неоднозначен, и про который в репорте нет ничего:
MODULE A;
TYPE
P* = POINTER TO RECORD foo* : INTEGER END;
END A.
А вот, похоже, экспортировать указатели на анонимные записи вряд ли можно.
Но тогда, по аналогии, нельзя экспортировать и указатели на процедуры?
Ну, во первых указателей на процедуры в Обероне нет, есть лишь процедурные типы (пофиг как оно реализуется технически).
Во-вторых, почему нельзя? Процитированное тобою имеет несколько иные акценты:
1. If a type T is defined as POINTER TO T1 (see 6.4), the identifier T1 can be declared textually
following the declaration of T, but it must lie within the same scope.
То есть это исключение из правил, то есть правило (1) введено для того, чтобы ослабить требования объявлений сверху-внизу для указателей. Всего лишь.
-
Тут говорится о валидности объявлений (declaration, процесса объявления новых типо), я же говорю и спрашиваю о экспорте и импорте. То есть не про объявления, это разные понятия.
В оберонах модификатор экспорта -- это часть декларации. Так в чём проблема-то?
На тип этот модификатор никак не влияет. То есть не входит в сигнатуру.
-
Ну, во первых указателей на процедуры в Обероне нет, есть лишь процедурные типы (пофиг как оно реализуется технически).
А, да, процедурные типы же без указателей объявляются, так что всё нормально тут... Вроде бы...
-
Поля записи, отмеченные знаком экспорта, должны быть доступны через экспортированный тип указателя на эту запись, независимо от того, экспортирован тип записи или нет, именован или нет.
Исходя из этого, объявить переменную типа экспортированный указатель на не экспортированную или безымянную запись и создать экземпляр он может, иначе полная бессмыслица получится.
-
Исходя из этого, объявить переменную типа экспортированный указатель на не экспортированную или безымянную запись и создать экземпляр он может, иначе полная бессмыслица получится.
Это будет аналогией экземпляра класса сишарпа -- в куче создать можно, а на стеке -- нет...
-
Это будет аналогией экземпляра класса сишарпа -- в куче создать можно, а на стеке -- нет...
Мы и говорим про указатель
-
Это будет аналогией экземпляра класса сишарпа -- в куче создать можно, а на стеке -- нет...
Мы и говорим про указатель
Блекбоксёры постоянно ставят в достоинство КП то, что в нём записи можно создавать не только в куче, но и на стеке, в отличие от Явы, где все объекты создаются только на куче.
Этим они объясняют высокую производительность свой шины сообщений.
Экспорт же записи только через указательный тип не позволит использовать такие записи на куче и сводит на нет это преимущество оберонов перед явой.
Так что с точки зрения оберонщиков такой экспорт лишён смысла...
-
Лично моя позиция - не запрещено + имеет смысл = разрешено.
-
"за сценой", дополнительно - не забудьте
1. Вирт и так ограничил по максимуму язык
2. Мы не имеем четкого представления куда идет эта реализация
3. УЖЕ получается не совсем то, что хотелось (в частности , строгости и непротиворечивости).
4. Любое ограничение уменьшает выгоду от простоты языка и накладывает трудно прогнозируемые ограничения на область использования
5. Мы пока еще неспособны аргументировать введение ограничений на хорошем уровне.
-
Блекбоксёры постоянно ставят в достоинство КП то, что в нём записи можно создавать не только в куче, но и на стеке, в отличие от Явы, где все объекты создаются только на куче.
Этим они объясняют высокую производительность свой шины сообщений.
Во всех Оберонах так - записи создаются в стеке, динамические(через указатель) экземпляры в куче.
Экспорт же записи только через указательный тип не позволит использовать такие записи на куче и сводит на нет это преимущество оберонов перед явой.
Для этого и предназначены opaque типы. Там, где нужны статические объекты в стеке - нужно использовать записи, естественно, экспортируя тип записи.
-
"за сценой", дополнительно - не забудьте
1. Вирт и так ограничил по максимуму язык
2. Мы не имеем четкого представления куда идет эта реализация
3. УЖЕ получается не совсем то, что хотелось (в частности , строгости и непротиворечивости).
4. Любое ограничение уменьшает выгоду от простоты языка и накладывает трудно прогнозируемые ограничения на область использования
5. Мы пока еще неспособны аргументировать введение ограничений на хорошем уровне.
Все мои предложения основаны на практической необходимости возникающей при попытке написания либ и биндингов. Попозже попробую оформить примеры.
-
Все мои предложения основаны на практической необходимости возникающей при попытке написания либ и биндингов. Попозже попробую оформить примеры.
давайте посмотрим - только в нашем случае биндинги должны быть к js- либам, ну и учтите, что для работы с js можно всегда ввести дополнительные фичи не затрагивая основной язык.
-
Поля записи, отмеченные знаком экспорта, должны быть доступны через экспортированный тип указателя на эту запись, независимо от того, экспортирован тип записи или нет, именован или нет.
Исходя из этого, объявить переменную типа экспортированный указатель на не экспортированную или безымянную запись и создать экземпляр он может, иначе полная бессмыслица получится.
Гм. А как на счет вот такого примера:
MODULE M;
TYPE
R = RECORD foo* : INTEGER END;
P* = POINTER TO R;
END M.
-
Гм. А как на счет вот такого примера:
MODULE M;
TYPE
R = RECORD foo* : INTEGER END;
P* = POINTER TO R;
END M.
Репорт:
6.3 Record types
...
If a record type is exported, field identifiers that are to be visible outside the declaring module must
be marked.
Т.е., если тип-запись не экспортируется, то его поля не должны экспортироваться.
-
Гм. А как на счет вот такого примера:
MODULE M;
TYPE
R = RECORD foo* : INTEGER END;
P* = POINTER TO R;
END M.
Репорт:
6.3 Record types
...
If a record type is exported, field identifiers that are to be visible outside the declaring module must
be marked.
Т.е., если тип-запись не экспортируется, то его поля не должны экспортироваться.
Ну, если строго логически подходить к данному пункту, то это не так - тут сказано лишь, что если тип записи экспортируется, то все поля которые должны быть видимыми за пределеми модуля нужно промаркировать звездочкой. Однако тут не разобран случай когда тип записи не экспортируется.
Соответственно я вижу тут две возможности (и нам надо выбрать одну из них)
1) Такая ситуация, как приведенном мное исходнике, является ошибочной, и мы должны получить ошибку компиляции (с указанием на то, что сам тип записи не экспортируется).
2) Такая ситуация не ошибочна, и мы к полям записи можем получить доступ через указатель, но при этом экземпляры записи вне данного модуля создавать не можем.
-
Гм. А как на счет вот такого примера:
MODULE M;
TYPE
R = RECORD foo* : INTEGER END;
P* = POINTER TO R;
END M.
Думаю, так:
MODULE N;
IMPORT M;
VAR
p : M.P;
BEGIN
NEW( p );
p.foo := 1;
END N;
-
Только сейчас подумал о том, что такие путаные правила экспорта возможно обусловлены стремлением упростить инструмент генерации def-файлов, ведь тогда такой инструмент сводится к простому цитированию фрагментов модуля:
MODULE M;
TYPE
R* = RECORD foo*, foo2 : INTEGER END;
P* = POINTER TO R;
END M.
DEFINITION M;
TYPE
R = RECORD foo : INTEGER END;
P = POINTER TO R;
END M.
А если тип-запись не экспортируется, но при этом экспортируются его поля, то как тогда создать def? Ну, а если def-файлы в принципе не нужны, то тогда можно упростить правила и лепить метки экспорта где угодно.
-
1) Такая ситуация, как приведенном мное исходнике, является ошибочной, и мы должны получить ошибку компиляции (с указанием на то, что сам тип записи не экспортируется).
Сейчас оно именно так и работает (пишет ошибку).
2) Такая ситуация не ошибочна, и мы к полям записи можем получить доступ через указатель, но при этом экземпляры записи вне данного модуля создавать не можем.
Возможно так правильнее - тогда можно использовать запись без NEW внутри модуля. Хотя практического смысла пока не вижу.
-
Тут говорится о валидности объявлений (declaration, процесса объявления новых типо), я же говорю и спрашиваю о экспорте и импорте. То есть не про объявления, это разные понятия.
В оберонах модификатор экспорта -- это часть декларации. Так в чём проблема-то?
На тип этот модификатор никак не влияет. То есть не входит в сигнатуру.
Не входит в сигнатуру типа, но входит в сигнатуру модуля.
-
2) Такая ситуация не ошибочна, и мы к полям записи можем получить доступ через указатель, но при этом экземпляры записи вне данного модуля создавать не можем.
Эту идею ещё стоит обдумать, но мне кажется, что не стоит разрешать делать NEW для импортируемых типов. А объявлять переменные можно разрешать для любых импортируемых типов.
Таким образом, если экспортируемый тип предполагает размещение в куче, то его значение мы можем получить из импортированной процедуры. А если на стеке - то память выделится на стеке вне зависимости от того используем ли мы инициализатор из импортируемого модуля или нет. Если экспортируется указатель, а запись осталась скрытой, то инициализировать переменную получится только процедурой из того модуля.
То есть, указатель или запись влияют на поведение импорта только в этом ключе. А для доступа к полям, если они экспортированы, достаточно, чтобы хотя бы один типов указатель/запись были экспортированы.