Search code examples
delphidelphi-10.2-tokyo

Why can't the compiler find the overloaded version of my function?


Without Get being overloaded (using only the first definition of Get) this otherwise compiles ok:

program Project1;
{$APPTYPE CONSOLE}

uses SysUtils, Classes;

type
  TxALNameValuePair = record
    Name: ansistring;
    Value: ansistring;
    constructor Create(const AName, AValue: ansistring);
  end;
  TxALNameValueArray = TArray<TxALNameValuePair>;

  TxALHTTPClient = class(TObject)
    private
    protected
    public
      Function  Get(const aUrl:AnsiString;
                    const ARequestHeaderValues: TxALNameValueArray = nil): AnsiString; overload;  
      Function  Get(const aUrl:AnsiString;
                    const aRequestFields: TStrings;
                    const aEncodeRequestFields: Boolean=True;
                    const ARequestHeaderValues: TArray<TxALNameValuePair> = nil): AnsiString; overload;      
  end;

constructor TxALNameValuePair.Create(const AName, AValue: ansiString);
begin
  Name := AName;
  Value := AValue;
end;       

function TxALHTTPClient.Get(const aUrl: AnsiString;
  const ARequestHeaderValues: TxALNameValueArray): AnsiString;
begin    
end;

Function  TxALHTTPClient.Get(const aUrl:AnsiString;
              const aRequestFields: TStrings;
              Const aEncodeRequestFields: Boolean=True;
              const ARequestHeaderValues: TArray<TxALNameValuePair> = nil): AnsiString;
begin
end;

var
  aHttpCLient: TxALHTTPClient;
begin
  aHttpClient := TxALHTTPClient.Create;
  aHttpCLient.get('http://www.toto.com', [TxALNameValuePair.Create('Accept-Encoding', 'gzip')]);
  ReadLn;
end.

But when Get is overloaded it produces

[dcc64 Error] E2250 There is no overloaded version of 'Get' that can be called with these arguments

Why is the compiler not able to resolve this overload?


Solution

  • The problem here is that the dynamic array constructor you are using is producing an object of type array of TxALNameValuePair, but all of your overloads require the type to be TxALNameValueArray, and it seems that the compiler is not making the connection between array of TxALNameValuePair ==> TArray<T> for T => TAxTxALNameValuePair.

    The array can be implicitly converted to the correct type when there is no ambiguity introduced from an overload but otherwise it seems you have to provide that type information somehow. The easiest (and probably clearest) way is just to use a variable.

    var
      aHttpCLient: TxALHTTPClient;
      nvpArray : TxALNameValueArray;
    begin
      aHttpClient := TxALHTTPClient.Create;
      nvpArray := [TxALNameValuePair.Create('Accept-Encoding', 'gzip')];
      aHttpCLient.get('http://www.toto.com', nvpArray);
      ReadLn;
    end.
    

    You can also construct the array in place using a typed dynamic array constructor :

    var
      aHttpCLient: TxALHTTPClient;
    begin
      aHttpClient := TxALHTTPClient.Create;
      aHttpCLient.get('http://www.toto.com', 
                      TxALNameValueArray.Create(
                        TxALNameValuePair.Create('Accept-Encoding', 'gzip')
                      ));
      ReadLn;
    end.
    

    Otherwise, unless there's a special need for your own name-value pair record type you can just use the one that is supplied in System.Net.URLClient :

    program Project1;
    {$APPTYPE CONSOLE}
    
    uses SysUtils, Classes, System.Net.URLClient;
    
    type
      TxALHTTPClient = class(TObject)
        private
        protected
        public
          Function  Get(const aUrl:AnsiString;
                        const ARequestHeaderValues: TNameValueArray = nil): AnsiString; overload;
          Function  Get(const aUrl:AnsiString;
                        const aRequestFields: TStrings;
                        const aEncodeRequestFields: Boolean=True;
                        const ARequestHeaderValues: TNameValueArray = nil): AnsiString; overload;
      end;
    
    function TxALHTTPClient.Get(const aUrl: AnsiString;
      const ARequestHeaderValues: TNameValueArray): AnsiString;
    begin
    end;
    
    Function  TxALHTTPClient.Get(const aUrl:AnsiString;
                  const aRequestFields: TStrings;
                  Const aEncodeRequestFields: Boolean=True;
                  const ARequestHeaderValues: TNameValueArray = nil): AnsiString;
    begin
    end;
    
    var
      aHttpCLient: TxALHTTPClient;
    begin
      aHttpClient := TxALHTTPClient.Create;
      aHttpCLient.get('http://www.toto.com', [TNameValuePair.Create('Accept-Encoding', 'gzip')]);
      ReadLn;
    end.
    

    I'm guessing that this works simply because of compiler magic, being a system defined type.

    Further down this route, you can equally use TNetHeaders instead of TNameValueArray, the former simply being an alias of this type. You can also create your own alias like

    TxALNameValueArray = TNetHeaders;
    

    if you really want.


    Digging deeper, we can produce a minimal example showing the problem :

    program Project1;
    {$APPTYPE CONSOLE}
    
    type
      TDblArray = TArray<double>;
    
    procedure A(i : integer; da : TDblArray); overload;
    begin
    end;
    
    procedure A(s : string; da : TDblArray); overload;
    begin
    end;
    
    begin
      A(1, [1.0]);
    end.
    

    This does not compile with the same error.

    This does work, however:

    program Project1;
    {$APPTYPE CONSOLE}
    
    type
      TDblArray = array of double;
    
    procedure A(i : integer; da : TDblArray); overload;
    begin
    end;
    
    procedure A(s : string; da : TDblArray); overload;
    begin
    end;
    
    begin
      A(1, [1.0]);
    end.
    

    As does this :

    program Project1;
    {$APPTYPE CONSOLE}
    
    uses Types;
    
    procedure A(i : integer; da : TDoubleDynArray); overload;
    begin
    end;
    
    procedure A(s : string; da : TDoubleDynArray); overload;
    begin
    end;
    
    begin
      A(1, [1.0]);
    end.
    

    Maybe we want to call this a compiler bug? I'm not sure. Normal type resolution works forwards but with overload resolution it has to work backwards... this might be a halting problem situation in the general case. Could submit a QP if you feel strongly about it.