Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Delphi resolve overloaded functions with Pointer(typeless one) parameters?

Below are few overloaded functions. Try to guess which function of those would get called.

program Project2;
    {$APPTYPE CONSOLE}

uses
  Types, SysUtils;

procedure Some(const Buf); overload;
  begin
    Writeln('const-typeless')
  end;

//procedure Some(var Buf); overload;
//  begin
//    Writeln('var-typeless')
//  end;

//procedure Some(Buf :TByteDynArray); overload;
//  begin
//    Writeln('Byte dynamic array');
//  end;

procedure Some(Buf :array of Byte); overload;
  begin
    Writeln('Byte open array');
  end;

procedure Some(Buf :TArray<Byte>); overload;
  begin
    Writeln('TBytes AKA byte generic array');
  end;

//procedure Some(Buf :TBytes); overload;
//  begin
//    Writeln('TBytes AKA byte generic array');
//  end;

var p: pointer;

begin
  try
    { TODO -oUser -cConsole Main : Insert code here }
    WriteLn ('Calling overloaded procedure with Pointer parameter:');

    Write('  * nil: '); p := nil; Some(p);
    Write('  * garbage: '); p := Pointer(1); Some(p);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;

  ReadLn;
end.

In fact, the 2nd one is called and throws AV on its 2nd call. Given old VCL pattern of using Pointer and Integer interchangeably (such as TList and TStrings.Objects and TWinControl.Tag) that may cause unexpected AVs on a rather regular code.

{$T+} does not change the behavior, so it was not that Delphi thinks ^Byte is Pointer.

However declaring p: PInteger; fixes it. Also the open-array variant is not called for pointer, and is treated/name-mangled differently than generic-array variant. Dynamic array is name-mangled differently from generic array, so both can be used, yet at the call site ambiguous overload error would happen if both uncommented. However, if to compile with generic array disabled and dinamic array uncommented - the same weird behavior happens.

Why does the compiler resolve to dynamic/generic array when parameter is a Pointer, and resolve to constant typeless when parameter is PInteger ?

  • Related: How does Delphi resolve overloaded functions with integral parameters?
  • Related: why two aliases to "array of string" treated differently?
  • Related: QC 108978
  • Code from: http://www.sql.ru/forum/actualthread.aspx?tid=970289

PS. Opened QC 109019

like image 840
Arioch 'The Avatar asked Sep 25 '12 07:09

Arioch 'The


1 Answers

There's no documentation for this, so the best we can do is poke at the compiler and try to guess the reasoning behind its behaviour.

Now, a procedure with a typeless parameter can be passed any parameter, irrespective of its type. So, any sane overload resolution scheme has to consider the typeless parameter last, only when it has exhausted all other possible candidates. Otherwise it would always be chosen.

So with that, the behaviour can be explained.

  • When your parameter is of type, Pointer, that is assignment compatible with a dynamic array. Which means that the dynamic array overload can be selected.
  • When your parameter is any other pointer type, it is not assignment compatible with a dynamic array. And so the overload resolution falls back to the final possible candidate, the typeless parameter.

Ultimately this behaviour comes down to the fact that the compiler considers Pointer to be assignment compatible with any dynamic array. That this statement is fact is easy to confirm by experiment, however, I cannot find documentation for it.

like image 57
David Heffernan Avatar answered Nov 14 '22 10:11

David Heffernan