Значение, используемое как выходное, так и (не справочное) входное в цепочке методов - PullRequest
2 голосов
/ 19 июня 2020

Рассмотрим следующий минимальный пример объединения методов, где переменная с плавающей запятой устанавливается (с использованием параметра out) ранним методом, а затем передается (с использованием параметра const) более позднему методу в цепочке. :

program ChainedConundrum;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
  ValueType = Double;
  TRec = record
    function GetValue(out AOutput: ValueType): TRec;
    procedure ShowValue(const AInput: ValueType);
  end;

function TRec.GetValue(out AOutput: ValueType): TRec;
begin
  AOutput := 394;
  Result := Self;
end;

procedure TRec.ShowValue(const AInput: ValueType);
begin
  Writeln(AInput);
end;

var
  R: TRec;
  Value: ValueType = 713;

begin
  R.GetValue(Value).ShowValue(Value);
  Readln;
end.

Сначала я ожидал, что это напечатает число с плавающей запятой 394 (в каком-то формате), но это не так (обязательно); когда я собираю программу с использованием 32-разрядного компилятора Delphi 10.3.2, программа печатает 713. Пошаговое выполнение программы с использованием отладчика подтверждает, что начальное, предварительное GetValue значение Value передается в ShowValue.

Однако, если я построю это с помощью 64-битного компилятора, 394 печатается. Аналогичным образом, если я изменю ValueType с Double на Int32, я получу 394 в обеих версиях. Int64 дает 394 в 64-битном и 713 в 32-битном. Строки возвращают обновленное значение. Классы работают как записи. Однако методы класса, в отличие от методов экземпляра, всегда возвращают обновленное значение. И, конечно же, отказ от цепочки методов (R.GetValue(Value); R.ShowValue(Value)) делает то же самое.

Неудивительно, если я изменю параметр AInput в ShowValue с const (или недекорированного значения) на параметр var, я всегда получаю обновленное значение.

Мое заключение таково, что либо

  1. нельзя одновременно устанавливать и передавать переменную в цепочке таких методов, как это, или
  2. в компиляторе есть ошибка.

Мой вопрос: что это? А если это не разрешено, где об этом говорится в документации? Мне пока не удалось найти соответствующий отрывок. (Фраза «точка последовательности» кажется очень редко встречается где-нибудь рядом с фразой «Delphi» в WWW.)

1 Ответ

1 голос
/ 21 июня 2020

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

Я создал проблему RSP-29733 в Embarcadero Jira.

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

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

Следовательно, более естественным подходом кажется используйте параметр const [Ref]:

procedure ShowValue(const [Ref] AInput: ValueType);

Он имеет ту же семантику, что и недекорированный параметр const, но заставляет компилятор передавать переменную по ссылке, что позволяет избежать ошибки.

...