Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 251
zeus Avatar asked Mar 06 '23 18:03

zeus


1 Answers

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.

like image 88
J... Avatar answered May 10 '23 16:05

J...