Hairy Pixels <generic...@gmail.com> schrieb am So., 19. Juni 2022, 15:44:
> > > > On Jun 19, 2022, at 7:01 PM, Sven Barth via fpc-pascal < > fpc-pascal@lists.freepascal.org> wrote: > > > > 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): > > Firstly unrelated, I posted a question about generics which you probably > have the answer to and may have missed ( > https://www.mail-archive.com/fpc-pascal@lists.freepascal.org/msg55415.html). > I just joined the Lazarus forum also and mentioned this in a related topic > where another user seems to have stumbled on something similar. > 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. > > Also keep in mind that the expensive creation only happens once. > Afterwards it's "only" the price of an indirect call. > > > > 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. > > 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. > You misunderstand how function references work. Assume the following: === code begin === function Foo: LongInt; var f: reference to procedure; sum, i: LongInt; begin f := procedure begin sum := sum + i * 2; end; sum := 0; for i := 0 to 100 do f(); Result := sum; end; === code end === This is essentially equivalent to the following: === code begin === function Foo: LongInt; type TFunc = interface procedure Invoke; end; TCapturer = class(TInterfacedObject, TFunc) sum, i: LongInt; procedure TFunc.Invoke =TFunc_Invoke; procedure TFunc_Invoke; end; procedure TCapturer.TFunc_Invoke; begin sum := sum + i * 2; end; var capturer: TCapturer; keepalive: IInterface; f: TFunc; begin capturer := TCapturer.Create; keepalive := capturer; f := capturer; for capturer.i := 0 to 100 do f.Invoke(); Result := capturer.sum; end; === code end === As you can see the allocation only happens once and not all the time. 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). 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. Regards, Sven
_______________________________________________ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal