Использование `Deconstruct` как стандартного распаковщика значений

В языке давно есть система функций Deconstruct:

type
  t1 = auto class
    a, b: integer;
  end;
  
begin
  var a,b: integer;
  (new t1).Deconstruct(a,b);
  (1,2).Deconstruct(a,b);
end.

Но сейчас она используется в сахаре только как часть is-var:

  if t is System.Tuple<integer,integer>(var c; var d) then

Эта строчка, по сути, кроме вызова .Deconstruct делает только проверку t<>nil - которая далеко не всегда нужна. Как и весь if.

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

Может лучше распаковку всегда делать с помощью .Deconstruct?

  1. Не нужна доп. внутренняя локальная переменная для картежа. То есть:
    ##
    function f1 := (1,2);
    
    var (a,b) := f1;
    
    Будет превращаться в:
    ##
    function f1 := (1,2);
    
    var a,b: integer;
    f1.Deconstruct(a,b);
    
  2. Будет более стандартизированное поведение - ещё и расширяемое пользовательскими типами:
    type
      t1 = auto class
        a, b: integer;
      end;
      
    begin
      var (a,b) := new t1;
    end.
    

Есть ли с этим какие-то нетривиальные проблемы?

Я не против. Deconstruct появился в C# 7.0. Но у нас есть инсталлятор для Windows XP, базирующийся на Net 4.5 если не ошибаюсь. Там будет работать?

Что важно нам - это что он появился в .Net Framework 4.7:

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

С другой стороны, типы ValueTuple тоже не существует до в стандартных .dll до .Net Framework 4.7, и у них нету стандартных .Deconstruct во всех версиях .Net .

Я так понимаю, если описать эти .Deconstruct в PABCSystem и попытаться собрать компилятор под более старую версию .Net - оно упадёт? Тогда это можно будет сделать только с какой-то директивой вроде $ifdef:

{$ifdef .Net Frameword 4.7} // очень примерное название дефайна

// Только в этой .Net есть ValueTuple
procedure Deconstruct<T1>(self: ValueTuple<T1>; var v1: T1); extensionmethod :=
v1 := self.Item1;

{$else .Net Frameword 4.7}

// В этой .Net нету стандартных Deconstruct
procedure Deconstruct<T1>(self: Tuple<T1>; var v1: T1); extensionmethod :=
v1 := self.Item1;

{$endif .Net Frameword 4.7}

(поидее разница только в ValueTuple/Tuple, поэтому можно сильно сократить…)

ifdef в PABCSystem делать нельзя - он компилируется не для конкретного компьютера, а для всех

Разве RebuildStandartModules.pas не компилирует с аргументом /rebuild несколько раз - для разных версий .Net? А у него PABCSystem.pas в зависимостях, то есть создаётся новый PABCSystem.pcu при каждой компиляции.

Не понимаю, о чем Вы говорите. Можно откомпилировать, но .pcu в инсталляте один. И в нем либо вырезан кусок по ifdef либо нет. Для стандартных модулей ifdef бессмысленен