-1

The Execute method of Parallel.For has a TOmniIteratorDelegate parameter. But I'm unsure on how to assign a procedure to a variable of that type. The reason for doing this is that I do not want to use anonymous procedures.

Is this possible? If yes, can someone show me how to do it?

type
  TBookmark = record
    URL: String;
    PageTitle: String;
  end;

  PBookmark = ^TBookmark;

var
  FBookmarkList: TThreadList<PBookmark>;

procedure TfmMain.FormCreate(Sender: TObject);
begin
  FBookmarkList := TThreadList<PBookmark>.Create;

end;

procedure TfmMain.FormDestroy(Sender: TObject);
var
  B: PBookmark;
  L: TList<PBookmark>;
begin
  L := FBookmarkList.LockList;
  for B in L do
    Dispose(B);
  FBookmarkList.UnlockList;
  FBookmarkList.Free;
end;

procedure SetValue(const Value: TOmniValue);
begin
  // P := Value.ToRecord<PBookmark>;
  // P.PageTitle := P.URL;

end;

procedure TfmMain.btRefreshClick(Sender: TObject);
var
  L: TList<PBookmark>;
  P: TOmniIteratorDelegate<PBookmark>;
  t: IOmniParallelLoop<PBookmark>;
begin

  P := TOmniIteratorDelegate<PBookmark>(Addr(SetValue)); // <---- Program crashes at runtime on this line!

  L := FBookmarkList.LockList;
  try
    t := Parallel.ForEach<PBookmark>(L).NumTasks(5);
    t.Execute(P);

    vstBkmk.Clear;
    FvstBkmkIter := 0;
    vstBkmk.RootNodeCount := L.Count;
  finally
    FBookmarkList.UnlockList;
  end;

end;
Steve F
  • 1,527
  • 1
  • 29
  • 55
  • 1
    Why the downvotes? I have clearly described the problem, and provided the example code. – Steve F Dec 17 '19 at 19:57
  • 2
    You can't avoid anonymous methods, if that's what the signature of the method expects. If you pass a procedure or method with matching parameters list, then it will be wrapped in an auto created anon method. – David Heffernan Dec 17 '19 at 20:29
  • @DavidHeffernan Okay. That is what I have done in the code above. Why is the runtime error occurring? – Steve F Dec 17 '19 at 20:37
  • 2
    You've used a typecast to `TOmniIteratorDelegate`. Remove that cast. If the code fails to compile fix the compilation error. Don't hide it by casting it away. That's just telling lies to the compiler. – David Heffernan Dec 17 '19 at 20:55
  • Removing the typecast results in a compile error: "E2010 Incompatible types: 'OtlParallel.TOmniIteratorDelegate' and 'Procedure'" – Steve F Dec 18 '19 at 09:17
  • Right, that's exactly what I expected. So fixing the type mismatch is the correct solution. What you had done previously was to tell the compiler, that contrary to what it could see, you were passing something that really was the correct type. The compiler says, "ok, if you say so", and then it can fail at runtime, because it really didn't match. Your answer shows how to deal with the error correctly. – David Heffernan Dec 18 '19 at 11:32

1 Answers1

2

I got it to work by changing the definition of the SetValue procedure as illustrated in the code below. Thanks to David Heffernan for pointing me in the right direction.

procedure SetValue(const Value: PBookmark);
var
  P: PBookmark;
begin
  Value.PageTitle := Value.URL;
end;

procedure TfmMain.btRefreshClick(Sender: TObject);
var
  L: TList<PBookmark>;
  P: TOmniIteratorDelegate<PBookmark>;
  t: IOmniParallelLoop<PBookmark>;
begin

  P := SetValue;

  L := FBookmarkList.LockList;
  try
    t := Parallel.ForEach<PBookmark>(L).NumTasks(5);
    t.Execute(P);

    vstBkmk.Clear;
    FvstBkmkIter := 0;
    vstBkmk.RootNodeCount := L.Count;
  finally
    FBookmarkList.UnlockList;
  end;

end;
Steve F
  • 1,527
  • 1
  • 29
  • 55