rgdawson 8 Posted December 21, 2024 I was experimenting with inline variable definitions and came across a case that I do not understand, so I made a very simple example. See Foo1 and Foo2 below. The only difference is where I define the variables. No type inference going on, nothing that unusual to my eyes, except that the type IShared<T>, from Spring4D, is defined as reference to function: T. Foo2 will not compile and I get an error: E2250 There is no overloaded version of 'Post' that can be called with these arguments. procedure Foo1; {<--Compiles} var Http: IShared<TIdHttp>; Request : IShared<TStringStream>; Response : IShared<TStringStream>; begin Http := Shared.Make(TIdHttp.Create); Request := Shared.Make(TStringStream.Create('Foo')); Response := Shared.Make(TStringStream.Create); Http.Post('Foo', Request, Response); end; procedure Foo2; {<-- Will not compile} begin var Http: IShared<TIdHttp>; var Request: IShared<TStringStream>; var Response: IShared<TStringStream>; Http := Shared.Make(TIdHttp.Create); Request := Shared.Make(TStringStream.Create('Foo')); Response := Shared.Make(TStringStream.Create); Http.Post('Foo', Request, Response); {<--Fails on this line} end; Can someone explain what is going on here? Share this post Link to post
Remy Lebeau 1581 Posted December 21, 2024 (edited) I can reproduce the problem in a simple example that doesn't involve Spring4D (however, I get an "E2010 Incompatible types" error instead of an E2250) : type IShared<T> = reference to function: T; Shared = class class function Make<T: class>(AObj: T): IShared<T>; end; TSharedImpl<T: class> = class(TInterfacedObject, IShared<T>) FObj: T; constructor Create(AObj: T); destructor Destroy; override; function Invoke: T; end; TTest = class end; TTester = class procedure DoTest(AObj: TTest); end; class function Shared.Make<T>(AObj: T): IShared<T>; begin Result := TSharedImpl<T>.Create(AObj) as IShared<T>; end; constructor TSharedImpl<T>.Create(AObj: T); begin inherited Create; FObj := AObj; end; destructor TSharedImpl<T>.Destroy; begin FObj.Free; inherited Destroy; end; function TSharedImpl<T>.Invoke: T; begin Result := FObj; end; procedure TTester.DoTest(AObj: TTest); begin //... end; procedure Foo1; var Tester : IShared<TTester>; TestObj : IShared<TTest>; begin Tester := Shared.Make(TTester.Create); TestObj := Shared.Make(TTest.Create); Tester.DoTest(TestObj); // <-- Compiles OK! end; procedure Foo2; begin var Tester: IShared<TTester>; var TestObj: IShared<TTest>; Tester := Shared.Make(TTester.Create); TestObj := Shared.Make(TTest.Create); Tester.DoTest(TestObj); // <-- E2010 Incompatible types: 'TTest' and 'IShared<TTest>' Tester.DoTest(TestObj()); // <-- Compiles OK! end; I have now reported this issue to Embarcadero: RSS-2613: Anonymous Method is called differently depending on whether it is declared as an Inline Variable or not Edited December 22, 2024 by Remy Lebeau 3 Share this post Link to post
Stefan Glienke 2131 Posted December 22, 2024 Most simple case to repro to compiler error: procedure X(i: Integer); begin end; procedure Y; begin var f: TFunc<Integer>; X(f); end; 1 Share this post Link to post
Remy Lebeau 1581 Posted December 22, 2024 7 hours ago, Stefan Glienke said: Most simple case to repro to compiler error: Show off 😉 7 hours ago, Stefan Glienke said: procedure X(i: Integer); begin end; procedure Y; begin var f: TFunc<Integer>; X(f); end; Thanks, I have added it to the bug report. 3 Share this post Link to post
Pat Foley 54 Posted December 22, 2024 (edited) How are the () implemented then are they to be implied? procedure X(i: Integer); begin end; procedure Y; begin var f: TFunc<Integer>; //X(f); You need give the compiler a "Clue" X(f()); //runs //(procedure begin Beep; end); Boo (procedure begin Beep; end) (); //Yay! //In VBA need use either Call or add (); 'To even add a line of code. end; Edited December 22, 2024 by Pat Foley Oops should read compiles does not 'run' as is. Share this post Link to post
pmcgee 27 Posted 3 hours ago On 12/22/2024 at 9:28 PM, Stefan Glienke said: Most simple case to repro to compiler error: procedure X(i: Integer); begin end; procedure Y; begin var f: TFunc<Integer>; X(f); end; Wait. We DO want a compiler error here, right?? X takes an integer, not a TFunc<Integer>. It makes sense that this should need to be X( f() ). 1 Share this post Link to post
Uwe Raabe 2137 Posted 3 hours ago The problem is inconsistency, as it compiles when f is declared as a local variable. Also see the example in the comment of Jost Riedel in the mentioned QP issue. procedure X(i: Integer); begin end; procedure Y1; var f: TFunc<Integer>; begin X(f); // compiles end; procedure Y2; begin var f: TFunc<Integer>; X(f); // fails end; 1 Share this post Link to post
pmcgee 27 Posted 3 hours ago Ok, I get it. I had the bushy end of the pineapple. 🙂 So, we want it to complain in BOTH cases. Yes? Share this post Link to post
Uwe Raabe 2137 Posted 2 hours ago While the inconsistency is obvious, there might be different opinions about which behavior is correct. One can argue that the local variable case is older and thus takes precedence. That would also take care of existing code staying compatible. Throwing an error on both cases would emphasize the type safety, but may cause some user complaints. Share this post Link to post