<div dir="auto"><div><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Hairy Pixels <<a href="mailto:genericptr@gmail.com" target="_blank" rel="noreferrer">genericptr@gmail.com</a>> schrieb am So., 19. Juni 2022, 15:44:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
<br>
> On Jun 19, 2022, at 7:01 PM, Sven Barth via fpc-pascal <<a href="mailto:fpc-pascal@lists.freepascal.org" rel="noreferrer noreferrer" target="_blank">fpc-pascal@lists.freepascal.org</a>> wrote:<br>
> <br>
> As I can see neither Anthony's nor Ryan's mail, but I can see them in the archive, I'll use Jonas mail for some general replies (please CC me when replying):<br>
<br>
Firstly unrelated, I posted a question about generics which you probably have the answer to and may have missed (<a href="https://www.mail-archive.com/fpc-pascal@lists.freepascal.org/msg55415.html" rel="noreferrer noreferrer noreferrer" target="_blank">https://www.mail-archive.com/fpc-pascal@lists.freepascal.org/msg55415.html</a>). I just joined the Lazarus forum also and mentioned this in a related topic where another user seems to have stumbled on something similar.<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">I have replied on the forum. But if you want a response to your other mail please reply to your own mail with me in CC, cause I can see it only in the archive. </div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> Also keep in mind that the expensive creation only happens once. Afterwards it's "only" the price of an indirect call. <br>
> <br>
<br>
The performance problem will surfice if you use a reference inside a function which is called often. Lets say you decided to use a reference as a general callback type because it’s convenient not to consider “is nested” or “of object” and then call this from within a function which is called in a tight loop.<br>
<br>
Depending on what you’re doing this extra allocation of the interface could totally blow your program out of the water but this isn’t apparent to the programer who merely sees what they’re doing a simple callback. For this reason you can’t rely on references as an all purpose callback type and if performance is important you need to make duplicate functions which take different types of functions pointers, hence our desire for a generalized function pointer that that doesn’t do the interface allocation if there’s no passing of the reference outside the calling scope.<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">You misunderstand how function references work. </div><div dir="auto"><br></div><div dir="auto">Assume the following:</div><div dir="auto"><br></div><div dir="auto">=== code begin ===</div><div dir="auto"><br></div><div dir="auto">function Foo: LongInt;</div><div dir="auto">var</div><div dir="auto"> f: reference to procedure;</div><div dir="auto"> sum, i: LongInt;</div><div dir="auto">begin</div><div dir="auto"> f := procedure</div><div dir="auto"> begin</div><div dir="auto"> sum := sum + i * 2;</div><div dir="auto"> end;</div><div dir="auto"> sum := 0;</div><div dir="auto"> for i := 0 to 100 do</div><div dir="auto"> f();</div><div dir="auto"> Result := sum;</div><div dir="auto">end;</div><div dir="auto"><br></div><div dir="auto">=== code end ===</div><div dir="auto"><br></div><div dir="auto">This is essentially equivalent to the following:</div><div dir="auto"><br></div><div dir="auto">=== code begin ===</div><div dir="auto"><br></div><div dir="auto">function Foo: LongInt;</div><div dir="auto">type</div><div dir="auto"> TFunc = interface</div><div dir="auto"> procedure Invoke;</div><div dir="auto"> end;</div><div dir="auto"> TCapturer = class(TInterfacedObject, TFunc)</div><div dir="auto"> sum, i: LongInt;</div><div dir="auto"> procedure TFunc.Invoke =TFunc_Invoke;</div><div dir="auto"> procedure TFunc_Invoke;</div><div dir="auto"> end;</div><div dir="auto"><br></div><div dir="auto"> procedure TCapturer.TFunc_Invoke;</div><div dir="auto"> begin</div><div dir="auto"> sum := sum + i * 2;</div><div dir="auto"> end;</div><div dir="auto"><br></div><div dir="auto">var</div><div dir="auto"> capturer: TCapturer;</div><div dir="auto"> keepalive: IInterface;</div><div dir="auto"> f: TFunc;</div><div dir="auto">begin</div><div dir="auto"> capturer := TCapturer.Create;</div><div dir="auto"> keepalive := capturer;</div><div dir="auto"><br></div><div dir="auto"> f := capturer;</div><div dir="auto"> for capturer.i := 0 to 100 do</div><div dir="auto"> f.Invoke();</div><div dir="auto"> Result := capturer.sum;</div><div dir="auto">end;</div><div dir="auto"><br></div><div dir="auto">=== code end ===</div><div dir="auto"><br></div><div dir="auto">As you can see the allocation only happens once and not all the time. </div><div dir="auto">What might be worse however is the optimization behavior as in this example the compiler wouldn't optimize the counter variable into a regvar with enabled optimizations (however in case of a nested function the compiler wouldn't do this either if the function isn't inlined). </div><div dir="auto"><br></div><div dir="auto">And even if you do the assignment of the function variable inside the loop you "merely" get the reference counting as a side effect and not a whole allocations. </div><div dir="auto"><br></div><div dir="auto">Regards,</div><div dir="auto">Sven </div></div>