Oberon space

General Category => Общий раздел => Тема начата: Berserker от Апрель 13, 2011, 06:34:54 pm

Название: Потеря идентификатора модуля в Delphi
Отправлено: Berserker от Апрель 13, 2011, 06:34:54 pm
Столкнулся с забавной проблемой во время написания кода на Delphi. Связана она с тем, что в методах класса все поля и методы класса перекрывают другие идентификаторы с такими же именами. Обратиться к идентификаторам этого же модуля точно можно используя полную нотацию: ModuleName.IdentName. Дело становится хуже, если обратится нужно к одному из модулей в секции USES. И вот почему.

Класс TForm (диалоговое окно) имеет поле Controls - дочерние контролы. С другой стороны, есть и используется одноимённый модуль Controls, из которого, нам, например, нужна пара констант. В результате Controls, Self.Controls указывает на поле, ModuleName.Controls выдаёт ошибку об отсутствии идентификатора Controls. То есть указать полное имя константы становится невоможным.

Решение найдено в обходном путе.

UNIT ModuleName;
USES ..., Controls;
...
CONST mbLeft = Controls.mbLeft;
...
...ModuleName.mbLeft...

то есть в импорте константы, а вернее создании её синонима.

PS. Если же у объекта будет ещё и поле, совпадающее с именем текущего модуля, то результат будет крайне плачевным. Из чего делаю вывод, что автоматический импорт идентификаторов в текущую область видимости есть зло, которого, к счастью, нет в Оберонах.
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: DIzer от Апрель 13, 2011, 09:07:57 pm
Не понимаю... "ModuleName.Controls" в моем понимании и должно выдавать такую ошибку.  а разве Controls.mbleft - не срабатывает?
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: Berserker от Апрель 13, 2011, 10:27:20 pm
Controls.mbleft обращается к TForm.Controls. Указать, что ты хочешь обратиться именно к модулю Controls, а не полю объекта, невозможно.
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: DIzer от Апрель 14, 2011, 03:35:42 am
Controls.mbleft обращается к TForm.Controls. Указать, что ты хочешь обратиться именно к модулю Controls, а не полю объекта, невозможно.
Так и должно быть...Вот такой код работает без танцев:

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
if Button=mbleft then  ShowMessage('mbLeft');
end;
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: Berserker от Апрель 14, 2011, 06:43:37 pm
Работает, но нарушает принцип указания полных имён идентификаторов, коим я пользуюсь. И вообще, всегда должна быть возможность точно обратиться к любому идентификатору.
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: DIzer от Апрель 14, 2011, 07:17:59 pm
Работает, но нарушает принцип указания полных имён идентификаторов, коим я пользуюсь. И вообще, всегда должна быть возможность точно обратиться к любому идентификатору.
Серьезно  :) , даже в том случае когда одноименная локальная переменная перекрывает глобальную ?
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: Berserker от Апрель 14, 2011, 07:48:36 pm
Конечно. Когда локальная перекрывает глобальную, к глобальной обращаются как к UnitName.VarName.
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: DIzer от Апрель 14, 2011, 08:33:12 pm
Конечно. Когда локальная перекрывает глобальную, к глобальной обращаются как к UnitName.VarName.
Cурово, КП  например отказывается такое даже компилировать (и меня это почему то  не удивляет).
MODULE m;
  IMPORT  Log := StdLog,  In := i21sysIn,  Math;

 VAR f:INTEGER;    
PROCEDURE p*;
       VAR f:INTEGER;
    BEGIN
     f:=15;
        Log.Int(f);
       Log.Ln;
       Log.Int(m.f);
 END p;  
BEGIN
f:=10;
END m.
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: Berserker от Апрель 14, 2011, 09:02:22 pm
Значит в Оберонах существенная проблема. В паскалях традиционно можно обращаться ко всем идентификаторам модуля точно так же, как и к идентификаторам других модулей. Чем это вас смущает?

UNIT A;
USES B, C;

CONST
  q = 7;
  v1 = A.q;
  v2 = B.q;
  v3 = C.q;
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: DIzer от Апрель 14, 2011, 09:09:30 pm
Значит в Оберонах существенная проблема. В паскалях традиционно можно обращаться ко всем идентификаторам модуля точно так же, как и к идентификаторам других модулей. Чем это вас смущает?

UNIT A;
USES B, C;

CONST
  q = 7;
  v1 = A.q;
  v2 = B.q;
  v3 = C.q;
Меня ничего не смущает - наоборот , то что Вас смущает представляется мне естественным. Тот эффект про который вы говорите  не описан в ЯП - и я его последние 20 лет трактую (для себя) с позиции затенения локальной переменной... и до сих пор проблем не было..
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: Илья Ермаков от Апрель 14, 2011, 09:10:07 pm
Значит в Оберонах существенная проблема. В паскалях традиционно можно обращаться ко всем идентификаторам модуля точно так же, как и к идентификаторам других модулей. Чем это вас смущает?

В Борланд-Паскалях. В Аде - нет (насколько помню).

И это правильно, т.к. общий механизм "прорыва через перекрытие" сделать всё равно нельзя. Если у Вас процедура второго уровня, как Вы доберётесь до перекрытой переменной в объемлющей процедуре?
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: Berserker от Апрель 14, 2011, 09:34:44 pm
Не могу проверить в Аде, но сомневаюсь, что там по-другому.

Цитировать
И это правильно
Отнюдь. Сперва ради упрощения жизни вводится ошибковлекующее правило автоматического импорта идентификаторов в текущую область видимости для модулей и подпрограмм, а потом оказывается, что явно прямо обратиться к элементу родителя нельзя.

Посудите сами. Модули ко всем своим основополагающим функциям выполняют также и роль пространства имён. Это позволяет в любом модуле иметь на верхнем уровне столько непереопределяемых идентификаторов, сколько импортируется других модулей + 1.

MODULE A;
IMPORT B, C, D;

(* Область видимости: A, B, C, D *)

Тогда на уровне верхнем (пока без учёта подпрограмм) можем явно и безошибочно обращаться к любому идентификатору из 4-х указанных модулей. При этом они для нас равнозначны. Вероятность ошибки - 0.

A.Const
B.Const
C.Const
D.Const

Вернёмся к подпрограммам. В них создаётся новая область видимости и туда записываются лишь идентификаторы модулей. И снова всё чётко и явно.

PROCEDURE Proc;
CONST
  Const = B.Const;

Проблема возникает во вложенных подпрограммах по одной простой причине. Потому что отношение "подпрограмма - дочерняя подпрограмма" само по себе образует псевдомодуль со своей областью видимости, типами, константами и т.д. Только это уже подлиннее цепочка: A -> Proc -> ChildProc. Решение просто - позволить работать синтаксису Proc.Const для родительских подпрограмм и запретить переопределять ключевые идентификаторы пространств имён. То есть в цепочке A -> Proc -> ChildProc на уровне ChildProc не должно быть локальных имён A, B, C, D, Proc.
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: Berserker от Апрель 14, 2011, 09:38:47 pm
В доказательство того, что цепочки подпрограммы сами есть модули, приведу пример из недавнего кода. Модуль из 366 строк, 1 процедура, никаких глобальных переменных. Зато сама это процедура является модулем по отношению к цепочке (10) дочерних, что объявлены в ней.
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: DIzer от Апрель 14, 2011, 09:50:35 pm
В доказательство того, что цепочки подпрограммы сами есть модули, приведу пример из недавнего кода. Модуль из 366 строк, 1 процедура, никаких глобальных переменных. Зато сама это процедура является модулем по отношению к цепочке (10) дочерних, что объявлены в ней.
Да причем тут это - в примере ,который вы привели выше (работающем) переменные имели один уровень глобальности. при понижении его (переходе к локальной области видимости) действует правило затенения.. в стандартном Паскале оно постулируется, когда борланды расширяли язык - они просто следовали этому принципу.
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: Berserker от Апрель 14, 2011, 10:09:40 pm
Правило затемнения - отлично. Но при чём тут оно к возможности при этом обращаться к любому идентификатору по полному имени? Вы вспомните файловую систему. Краткое имя обращается к файлу в текущем каталоге, но кто мешает явно указать путь до родительского? В чём концептуальная проблема?
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: Илья Ермаков от Апрель 14, 2011, 11:43:37 pm
По полному имени обращаемся к внешнему идентификатору. Внутри модуля его имя неизвестно. Его самого ещё как бы нет. Даже технически - модуль только компилируется, откуда ему быть.

Ваша логика тоже понятна, и не менее логична, чем моя :)
Но к чему огород городить (в случае, если полная квалификация в языке обязательна). Тупее - так, как есть в Обероне. Тупее = меньше мест для каких-то потенциальных проблем.
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: DIzer от Апрель 15, 2011, 07:12:31 am
Правило затемнения - отлично. Но при чём тут оно к возможности при этом обращаться к любому идентификатору по полному имени? Вы вспомните файловую систему. Краткое имя обращается к файлу в текущем каталоге, но кто мешает явно указать путь до родительского? В чём концептуальная проблема?
Вы про что вообще говорите: 1. Про свое ЛИЧНОЕ мироощущение  2. Общепринятые нормы  3. Ошибку в компиляторе Делфи(его несоответствие нормам Объектного Паскаля),
4. Несоответствие  Объектного Паскаля  общепринятым нормам.?
Я так понял (из исходного сообщения), что о п.3 и п.4 и ответил вам -т.е. не обнаружил ни ошибки  ни разрыва в моем понимании Делфи и общих принципов (слава богу).
Название: Re:Потеря идентификатора модуля в Delphi
Отправлено: Berserker от Апрель 15, 2011, 09:38:14 am
По полному имени обращаемся к внешнему идентификатору. Внутри модуля его имя неизвестно. Его самого ещё как бы нет. Даже технически - модуль только компилируется, откуда ему быть.

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

Правило затемнения - отлично. Но при чём тут оно к возможности при этом обращаться к любому идентификатору по полному имени? Вы вспомните файловую систему. Краткое имя обращается к файлу в текущем каталоге, но кто мешает явно указать путь до родительского? В чём концептуальная проблема?
Вы про что вообще говорите: 1. Про свое ЛИЧНОЕ мироощущение  2. Общепринятые нормы  3. Ошибку в компиляторе Делфи(его несоответствие нормам Объектного Паскаля),
4. Несоответствие  Объектного Паскаля  общепринятым нормам.?
Я так понял (из исходного сообщения), что о п.3 и п.4 и ответил вам -т.е. не обнаружил ни ошибки  ни разрыва в моем понимании Делфи и общих принципов (слава богу).
Я говорю про практику. Делфи, Free Pascal, Virtual Pascal как минимум поддерживают нотацию обращения к своему модулю. Но при этом они не поддерживают чуть более длинную нотацию, чтобы от имени своего модуля перейти к другим модулям: A.B.Const. Вот эта длинная нотация помогла бы решить проблему. Ну и в целом высказал пожелание, чтобы и к подпрограммам применить это правило и дать возможность ссылаться на Proc.Consts, указав, что отношение между подпрограммой и дочерней подпрограммой точно такие же, как между модулем и подпрограммами верхнего уровня.