2

This question is related to my other one and I hope to get some ideas from it:

Is it possible for a local managed variable (record, interface, ...) to survice the local scope and "travel to" another one without using any explicit out/var parameters or result values?

Sorry if this sounds strange, but this would allow me to create a managed object inside a called method which will only be destroyed when the calling method ends, not the one it has been created in, while the whole process is entirely transparent to the caller (this is the main goal). The caller doesn't have to declare anything.

First hacky idea comes here:

(Mis-)Use the automagically created wrapper object for anonymous methods and attach data to it. My assumption is: this object is created in the callers local scope, lives during the callees local scope (so the callee can attach data to it), and lives on until the end; of the caller.

Is it possible to attach data to this wrapper object? Apart from hackyness: has it any chance of working?

Edit: Maybe an easier phrasing for the question could be: "How to pass a result value from a function without using any parameters or function result?"

Edit2: Writing some code makes me wonder whether I should let it go:

function TForm1.L<T>(Func: TFunc<T>):T;
var
  Value: T;
begin
  Result := Func;

  // now attach something to the anon wrapper of Func
end;

function TForm1.O<T>(Value: T): T;
begin
  Result := T;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  List: TList;
begin
  for Item in L(O<TList>(List)) do
  begin

  end;

  // List should be destroyed here
end;

I think I should.

Community
  • 1
  • 1
Heinrich Ulbricht
  • 10,064
  • 4
  • 54
  • 85
  • 1
    Your idea of using variable capture will work but it sounds like it will be more complex and opaque than just passing parameters. For your way you'd need to pass anon func. How would that really help. – David Heffernan Nov 10 '11 at 13:58
  • `"How to pass a result value from a function without using any parameters or function result?"`: How would that look like, even in pseudo code, assuming something magic exists? The not-useful-answer to the actual question is: use global variables. – Cosmin Prund Nov 10 '11 at 14:09
  • 5
    Which problem are you trying to solve here? In general, such hidden dependencies (that method B depends on method A being called first) is generally a hindrance when it comes to code understanding and later change. – Lasse V. Karlsen Nov 10 '11 at 14:09
  • Hm somehow I thought I could solve it with just a single call. I just want transparent garbage collection for my list. That's all. – Heinrich Ulbricht Nov 10 '11 at 14:13
  • 1
    @HeinrichUlbricht, I recommend using explicit destruction, it's much less error-prone and really not that difficult. Just use `FreeandNil(MyObject);` when you're done. Use a `try .. finally` block to make sure the destruction happens. – Johan Nov 10 '11 at 14:26
  • I agree with Johan. Delphi is not garbage collected: ignoring that fact is "swimming against the current", it'll be hard, hacky and difficult to read. Better use the true-and-tested Delphi way: explicit allocation, try, finally - explicit destruction. – Cosmin Prund Nov 10 '11 at 14:30
  • Me: the guys have a point. Brain: http://icanhascheezburger.com/2007/09/25/screw-dis-no-wants/ – Heinrich Ulbricht Nov 10 '11 at 14:59
  • 1
    You could use an interface: it's reference counted, so will be destroyed automatically when you stop using it. Just remember not to mix object and interface references to the same object - refer to a specific object via one or the other only. – David Nov 10 '11 at 15:22
  • The whole point of function L and O sharing variable values including managed types is that the caller/callee have an explicit relationship because of the parameter list in the call from caller to the callee. Destroying that is unholy. If the two need to share something, then make them normal methods inside a class, each instance of that class contains its state, and then have the object itself freed when the last user of it goes out of scope (TInterfacedObject). Definitely don't make such methods as methods of your Form. – Warren P Nov 10 '11 at 19:53
  • @Warren Nah, the form is just from a quickly created test project. I won't ever make this part of my form! – Heinrich Ulbricht Nov 10 '11 at 20:01

1 Answers1

4

Sorry if this sounds strange, but this would allow me to create a managed object inside a called method which will only be destroyed when the calling method ends, not the one it has been created in. This way I don't have to use out/var variables or return values (which is effectively my goal).

The managed local variable from the CALLED method need to, well, "travel" to the calling method. The only defined methodologies for something like that to happen is to use var, out or return the actual value. That's because all "managed" data types that can be "transported" are reference-counted. This includes Interfaces and strings.

Use the automagically created wrapper object for anonymous methods and attach data to it. My assumption is: this object is created in the callers local scope, lives during the callees local scope (so the callee can attach data to it), and lives on until the end; of the caller.

Delphi generates an actual TInterfacedObject descendents for anonymous methods. It'll generate ONE such descendent for each method/procedure that declares anonymous methods. The name of the generated object will be based on the name of the procedure where the anonymous method is declared. This objects has methods, one method for each anonymous methods used. It also has data fields: one field for each local variable used in the anonymous method, plus a reference to the object you're operating on.

See here for a detailed explanation: How and when are variables referenced in Delphi's anonymous methods captured?

The idea is, you can attach data fields to the anonymous method by simply declaring local variables in the same procedure that's declaring the anonymous method, and using them within that anonymous method. You'll then be able to get hold of that data, but it would be a hacky, difficult way: you'd need to cast the anonymous method to the implementing object (the anonymous method is actually an interface, so it can be done). Then you'd need to use RTTI to get hold of the fields holding your data. Doesn't seem very useful to me.

Community
  • 1
  • 1
Cosmin Prund
  • 25,498
  • 2
  • 60
  • 104