Автор Тема: Потеря идентификатора модуля в Delphi  (Прочитано 15503 раз)

Berserker

  • Sr. Member
  • ****
  • Сообщений: 254
    • Просмотр профиля
Потеря идентификатора модуля в Delphi
« : Апрель 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. Если же у объекта будет ещё и поле, совпадающее с именем текущего модуля, то результат будет крайне плачевным. Из чего делаю вывод, что автоматический импорт идентификаторов в текущую область видимости есть зло, которого, к счастью, нет в Оберонах.

DIzer

  • Гость
Re:Потеря идентификатора модуля в Delphi
« Ответ #1 : Апрель 13, 2011, 09:07:57 pm »
Не понимаю... "ModuleName.Controls" в моем понимании и должно выдавать такую ошибку.  а разве Controls.mbleft - не срабатывает?

Berserker

  • Sr. Member
  • ****
  • Сообщений: 254
    • Просмотр профиля
Re:Потеря идентификатора модуля в Delphi
« Ответ #2 : Апрель 13, 2011, 10:27:20 pm »
Controls.mbleft обращается к TForm.Controls. Указать, что ты хочешь обратиться именно к модулю Controls, а не полю объекта, невозможно.

DIzer

  • Гость
Re:Потеря идентификатора модуля в Delphi
« Ответ #3 : Апрель 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;

Berserker

  • Sr. Member
  • ****
  • Сообщений: 254
    • Просмотр профиля
Re:Потеря идентификатора модуля в Delphi
« Ответ #4 : Апрель 14, 2011, 06:43:37 pm »
Работает, но нарушает принцип указания полных имён идентификаторов, коим я пользуюсь. И вообще, всегда должна быть возможность точно обратиться к любому идентификатору.

DIzer

  • Гость
Re:Потеря идентификатора модуля в Delphi
« Ответ #5 : Апрель 14, 2011, 07:17:59 pm »
Работает, но нарушает принцип указания полных имён идентификаторов, коим я пользуюсь. И вообще, всегда должна быть возможность точно обратиться к любому идентификатору.
Серьезно  :) , даже в том случае когда одноименная локальная переменная перекрывает глобальную ?

Berserker

  • Sr. Member
  • ****
  • Сообщений: 254
    • Просмотр профиля
Re:Потеря идентификатора модуля в Delphi
« Ответ #6 : Апрель 14, 2011, 07:48:36 pm »
Конечно. Когда локальная перекрывает глобальную, к глобальной обращаются как к UnitName.VarName.

DIzer

  • Гость
Re:Потеря идентификатора модуля в Delphi
« Ответ #7 : Апрель 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.

Berserker

  • Sr. Member
  • ****
  • Сообщений: 254
    • Просмотр профиля
Re:Потеря идентификатора модуля в Delphi
« Ответ #8 : Апрель 14, 2011, 09:02:22 pm »
Значит в Оберонах существенная проблема. В паскалях традиционно можно обращаться ко всем идентификаторам модуля точно так же, как и к идентификаторам других модулей. Чем это вас смущает?

UNIT A;
USES B, C;

CONST
  q = 7;
  v1 = A.q;
  v2 = B.q;
  v3 = C.q;

DIzer

  • Гость
Re:Потеря идентификатора модуля в Delphi
« Ответ #9 : Апрель 14, 2011, 09:09:30 pm »
Значит в Оберонах существенная проблема. В паскалях традиционно можно обращаться ко всем идентификаторам модуля точно так же, как и к идентификаторам других модулей. Чем это вас смущает?

UNIT A;
USES B, C;

CONST
  q = 7;
  v1 = A.q;
  v2 = B.q;
  v3 = C.q;
Меня ничего не смущает - наоборот , то что Вас смущает представляется мне естественным. Тот эффект про который вы говорите  не описан в ЯП - и я его последние 20 лет трактую (для себя) с позиции затенения локальной переменной... и до сих пор проблем не было..

Илья Ермаков

  • Full Member
  • ***
  • Сообщений: 177
    • Просмотр профиля
    • OberonCore
Re:Потеря идентификатора модуля в Delphi
« Ответ #10 : Апрель 14, 2011, 09:10:07 pm »
Значит в Оберонах существенная проблема. В паскалях традиционно можно обращаться ко всем идентификаторам модуля точно так же, как и к идентификаторам других модулей. Чем это вас смущает?

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

И это правильно, т.к. общий механизм "прорыва через перекрытие" сделать всё равно нельзя. Если у Вас процедура второго уровня, как Вы доберётесь до перекрытой переменной в объемлющей процедуре?

Berserker

  • Sr. Member
  • ****
  • Сообщений: 254
    • Просмотр профиля
Re:Потеря идентификатора модуля в Delphi
« Ответ #11 : Апрель 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.

Berserker

  • Sr. Member
  • ****
  • Сообщений: 254
    • Просмотр профиля
Re:Потеря идентификатора модуля в Delphi
« Ответ #12 : Апрель 14, 2011, 09:38:47 pm »
В доказательство того, что цепочки подпрограммы сами есть модули, приведу пример из недавнего кода. Модуль из 366 строк, 1 процедура, никаких глобальных переменных. Зато сама это процедура является модулем по отношению к цепочке (10) дочерних, что объявлены в ней.

DIzer

  • Гость
Re:Потеря идентификатора модуля в Delphi
« Ответ #13 : Апрель 14, 2011, 09:50:35 pm »
В доказательство того, что цепочки подпрограммы сами есть модули, приведу пример из недавнего кода. Модуль из 366 строк, 1 процедура, никаких глобальных переменных. Зато сама это процедура является модулем по отношению к цепочке (10) дочерних, что объявлены в ней.
Да причем тут это - в примере ,который вы привели выше (работающем) переменные имели один уровень глобальности. при понижении его (переходе к локальной области видимости) действует правило затенения.. в стандартном Паскале оно постулируется, когда борланды расширяли язык - они просто следовали этому принципу.

Berserker

  • Sr. Member
  • ****
  • Сообщений: 254
    • Просмотр профиля
Re:Потеря идентификатора модуля в Delphi
« Ответ #14 : Апрель 14, 2011, 10:09:40 pm »
Правило затемнения - отлично. Но при чём тут оно к возможности при этом обращаться к любому идентификатору по полному имени? Вы вспомните файловую систему. Краткое имя обращается к файлу в текущем каталоге, но кто мешает явно указать путь до родительского? В чём концептуальная проблема?