Am 17.09.2022 um 17:04 schrieb Hairy Pixels:
On Sep 17, 2022, at 9:43 PM, Sven Barth <pascaldra...@googlemail.com> wrote:
Then you didn't read my announcement mail deeply enough, cause it's mentioned
there!
Yes I just read that over and I remember it now. I feel like this not the same
behavior in other languages although I’d need to test. Most recently I’m using
Swift for my day job and I don’t recall ever having confusions like this come
up.
Complain to the developers of Delphi then.
I do however plan to extend anonymous (and nested) functions with a
syntax that allows to select whether a variable should be by-reference
or by-value. But that's still a bit off, cause I have other things to do
first.
And they are not pointers, but the variable is moved to an object instance
which implements the interface of the function reference.
“Moved to an object” makes me think the variable is copied but the reference
behavior you describe sounds like a pointer so I’m still not 100% clear on what
you mean.
Let's take your initial example and adjust it so that i will really be
captured:
=== code begin ===
{$mode objfpc}
{$modeswitch anonymousfunctions}
{$modeswitch functionreferences}
{$modeswitch arrayoperators}
program test;
uses
Cthreads, SysUtils, Classes;
type
TProc = reference to procedure;
TCallback = class(TThread)
private
proc: TProc;
public
constructor Create(p: TProc);
procedure Execute; override;
end;
procedure TCallback.Execute;
begin
proc();
Sleep(100);
end;
constructor TCallback.Create(p: TProc);
begin
inherited Create(true);
proc := p;
end;
procedure DoTest;
var
i: integer;
callback: TCallback;
callbacks: array of TCallback = ();
begin
for i := 1 to 4 do
begin
callback := TCallback.Create(procedure
begin
writeln('Invoked: ', i, ' id: ',
HexStr(TThread.CurrentThread));
end);
callback.Start;
callbacks += [callback];
end;
for i := 0 to High(callbacks) do
callbacks[i].WaitFor;
end;
begin
DoTest;
end.
=== code end ===
What the compiler will make of it will be as follows (the only
difference will be inside DoTest):
=== code begin ===
procedure DoTest;
type
TCapturer = class(TInterfacedObject, TProc)
i: integer;
procedure Anonymous1;
procedure TProc.Invoke = Anonymous1;
end;
procedure TCapturer.Anonymous1;
begin
writeln('Invoked: ', i, ' id: ', HexStr(TThread.CurrentThread));
end;
var
capturer: TCapturer;
capturer_keepalive: IUnknown;
callback: TCallback;
callbacks: array of TCallback = ();
begin
capturer := TCapturer.Create;
capturer_keepalive := capturer;
for capturer.i := 1 to 4 do
begin
callback := TCallback.Create(capturer as TProc);
callback.Start;
callbacks += [callback];
end;
for capturer.i := 0 to High(callbacks) do
callbacks[capturer.i].WaitFor;
end;
=== code end ===
That should make it clearer what is happening behind the scenes.
Even so I’m trying now to modifying the example by copying to a local variable
but I still see this same behavior suggesting there isn’t actually a copy. Why
is this?
When your callback is executed i might already have been changed!
Ok that makes sense now since it’s just a reference. So this would have worked
if I would have passed in i as a parameter and then stored it locally? I’m
thinking now how I can preserve a copy of the state in the scope for each
thread and I think local vars are the only way, correct? We need some more
thread based examples to help people understand I think because I’m finding all
sorts of edge cases updating a little thread library myself.
You need to move the creation of the thread to a separate nested
function (cause each thread will then have a separate capture object;
also this will work no matter if this is done in the main block or
inside a procedure/function/method):
=== code begin ===
function CreateCallback(aIndex: Integer): TCallback;
begin
Result := TCallback.Create(procedure
begin
writeln('Invoked: ', aIndex, ' id: ',
HexStr(TThread.CurrentThread));
end);
end;
var
i: integer;
callback: TCallback;
callbacks: array of TCallback = ();
begin
for i := 1 to 4 do
begin
callback := CreateCallback(i);
callback.Start;
callbacks += [callback];
end;
for i := 0 to High(callbacks) do
callbacks[i].WaitFor;
end.
=== code end ===
Regards,
Sven
_______________________________________________
fpc-pascal maillist - fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal