Почему в Delphi можно назначать себя?

Этот код в приложении с графическим интерфейсом компилируется и запускается:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Self := TForm1.Create(Owner);
end;

(проверено с Delphi 6 и 2009)

  • почему Self доступен для записи, а не только для чтения?
  • в каких ситуациях это может быть полезно?

Редактировать:

  • это также возможно в Delphi Prism? (Думаю, да, см. здесь)

Обновление: приложения/библиотеки Delphi, которые используют самоназначение:


person mjn    schedule 02.05.2009    source источник


Ответы (5)


Это не так плохо, как могло бы быть. Я только что протестировал его в Delphi 2009, и может показаться, что, хотя параметр Self не использует семантику const, которую вы, кажется, подразумеваете, он также не использует var, так что вы можете изменить все, что хотите, в своем методе, фактически не теряя ссылку вызывающего объекта на ваш объект. Это было бы очень плохо.

Что касается причины, почему, один из двух ответов. Либо простая оплошность, либо то, что предложил Марко: позволить вам передать Self параметру var.

person Mason Wheeler    schedule 02.05.2009

Может быть, разрешить переход к параметрам const или var?

Это может быть артефактом, так как система не имеет себя нигде слева от знака :=.

person Marco van de Voort    schedule 02.05.2009
comment
Для передачи себя как константы не требуется никаких специальных разрешений, поскольку это Я тоже может быть константой. Передача его в качестве параметра Var - это просто еще одна форма назначения, вопрос остается. - person Henk Holterman; 02.05.2009
comment
@Henk Holterman: Может быть, это просто для удобства: представьте, что есть функция (из какой-то библиотеки), которая требует ссылку на объект в качестве параметра var, даже если вы знаете, что на самом деле она ее не меняет. Если бы self нельзя было присвоить, вам пришлось бы объявить дополнительную переменную, присвоить ей self и передать эту переменную. Поскольку self назначаемый, вы можете просто передать self функции. - person dummzeuch; 30.03.2010

Назначение Self настолько нелогично и бесполезно, что эта «функция», вероятно, является недосмотром. Как и в случае с присваиваемыми константами, такие проблемы не всегда легко исправить.

Вот простой совет: не делайте этого.

person Henk Holterman    schedule 02.05.2009

На самом деле «Я» — это просто ссылка на имя места в стеке, в котором хранится адрес, указывающий на объект в куче. Принудительное использование только чтения для этой переменной возможно, по-видимому, дизайнер решил этого не делать. Я считаю решение произвольным.

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

Обновлено: в ответ на PatrickvL комментарий

«Переменная» «Я» не находится в стеке (насколько мне известно, никогда не бывает); Вместо этого его значение помещается в регистр (точнее, EAX) непосредственно перед вызовом любого метода объекта. –

Нет, у Self есть реальный адрес в памяти. Попробуйте этот код, чтобы убедиться в этом.

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(IntToStr(Integer(@Self)));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  newform: TForm;
  p: ^Integer;
begin
  Self.Caption := 'TheOriginal';
  newform := TForm.Create(nil);
  try
    newform.Caption := 'TheNewOne';
    // The following two lines is, technically, the same as
    //   Self := newform;
    p := Pointer(@Self);
    p^ := Integer(newform);
    ShowMessage(Self.Caption);  // This will show 'TheNewOne' instead of 'TheOriginal'
  finally
    Self.Free; // Relax, this will free TheNewOne rather than TheOriginal
  end;
end;
person Sake    schedule 02.05.2009
comment
Изменение значения в стеке может быть опасным — что произойдет со старым экземпляром объекта? Утечка памяти, я думаю. - person mjn; 02.05.2009
comment
@mjustin: нет проблем с изменением значения стека, это просто ссылка (указатель) на объект, вызывающий код / ​​владелец все равно будет иметь ссылку, чтобы окончательно освободить объект. - person mghie; 02.05.2009
comment
Self реализован как обычная ссылка на объект, даже как показывает этот вопрос. - person Henk Holterman; 02.05.2009
comment
Это не условное имя. Это встроено в язык. Вы не можете пойти против соглашения и использовать другое имя в своих собственных программах. - person Rob Kennedy; 03.05.2009
comment
"Переменная" Self не находится в стеке (насколько мне известно, никогда не бывает); Вместо этого его значение помещается в регистр (точнее, EAX) непосредственно перед вызовом любого метода объекта. - person PatrickvL; 30.03.2010
comment
Хм, ТАК потерял мой предыдущий комментарий, но ты не прав. Просто проигнорируйте тест @Self и посмотрите на разборку Self := nil, это станет чем-то вроде xor eax,eax - person PatrickvL; 20.04.2010
comment
Это должно называться оптимизацией. Да, большую часть времени Self не хранится в стеке. Но я считаю справедливым предположить, что он находится в стеке, поскольку компилятор всегда будет так выглядеть. - person Sake; 25.04.2010

Иногда, когда вы хотите оптимизировать метод настолько, насколько это возможно (не прибегая к сборке), «Self» может быть (ab) использован как «свободная» переменная — это может просто означать разницу между использованием стека и с помощью регистров.

Конечно, содержимое стека, скорее всего, уже присутствует в кеше ЦП, поэтому доступ к нему должен быть быстрым, но регистры еще быстрее.

В качестве примечания: я до сих пор скучаю по тем дням, когда я программировал на Amiga Motorola 68000 и имел роскошь 16 регистров данных и 16 адресных регистров... Я не могу поверить, что мир решил пойти с ограниченными 4 регистрами. линейки процессоров 80x86!

И последнее замечание: иногда я предпочитаю использовать Self, поскольку оптимизатор Delphi, ну, на самом деле не так хорошо оптимизирует. (По крайней мере, это меркнет по сравнению с теми хитростями, которые можно найти, например, в различных оптимизаторах LLVM.) IMHO и YMMV, конечно.

person PatrickvL    schedule 30.03.2010