Defer Mechanism for FreePascal lazarus / 64-FPC development ---------------------------------------------------------------------- Sniper · 2021-06-26 10:16 Everybody who writes in Golang know about it's defer mechanism. I found proposal of this useful thing for C (C2x) http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2542.pdf Do FPC core developers are interested in "defer" mechanism in freepascal? ---------------------------------------------------------------------- marcov · 2021-06-26 11:31 Sound like procedural form of exception handling. We already have such things in try.except and try.finally. ---------------------------------------------------------------------- Bi0T1N · 2021-06-26 11:49 Quote from: marcov on June 26, 2021, 01:31:17 pmSound like procedural form of exception handling. We already have such things in try.except and try.finally. I think that was also the outcome of the thread on the mailing list. ---------------------------------------------------------------------- PascalDragon · 2021-06-27 11:11 Quote from: Bi0T1N on June 26, 2021, 01:49:16 pmQuote from: marcov on June 26, 2021, 01:31:17 pmSound like procedural form of exception handling. We already have such things in try.except and try.finally. I think that was also the outcome of the thread on the mailing list. Correct. There is no need for a defer. A try … finally might be more verbose, but why sugar coat it? Also e.g. Lazarus helps you out there quite a bit by completing a try to a try … finally, a tryf to a try … finally with the cursor in the finally-block and a trye to a try … except. And then there's the nifty trycf which will create the following code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i VarName := TMyClassName.Create;try              finally  VarName.Free;end; Where the IDE highlights VarName and TMyClassName as editable blocks you can switch between with Tab (and editing VarName will edit both locations). ---------------------------------------------------------------------- AlexTP · 2021-06-27 11:29 @PascalDragon, thanks for pointing that out. Offtopic: I am your fan, trying to read all your last messages. ---------------------------------------------------------------------- Bogen85 · 2022-11-19 21:26 I know this an old post, but this can be done in FPC 3.3.1+. If Free Pascal has defer functionality was just asked in the Unofficial Free Pascal chat on discord so I thought I'd provide the same answer here. defer.pas Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$mode objfpc}{$H+}{$modeswitch anonymousfunctions}{$modeswitch functionreferences}{$modeswitch advancedrecords} unit defer; interface type  tDeferProc = reference to procedure;  tDeferred = array of tDeferProc;  tDefer = record  strict private    deferred: tDeferred;    class operator finalize (var self: tDefer);    class operator initialize (var self: tDefer);    procedure assign (const _deferred: tDeferProc);  public    property x: tDeferProc write assign;  end; implementation class operator tDefer.finalize (var self: tDefer);  var    i: integer;  begin    for i := high(self.deferred) downto low(self.deferred) do self.deferred[i]();  end; class operator tDefer.initialize (var self: tDefer);  begin    self.deferred := [];  end; procedure tDefer.assign (const _deferred: tDeferProc);  begin    insert(_deferred, deferred, length(deferred));  end; beginend. main.pas Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$mode objfpc}{$H+}{$modeswitch anonymousfunctions}{$modeswitch functionreferences} program main; uses  defer,  sysutils;   procedure main;    var      defer: tDefer;      y:     integer;     procedure deferred;      begin        inc(y);        writeln(format('Goodbye World! y = %d', [y]));      end;     begin      y       := 4;      defer.x := procedure      begin        writeln('First added runs last! y=', y);      end;       defer.x := procedure      begin        writeln('Last added runs first! y=', y);      end;       defer.x := tDeferProc(@deferred);      writeln('Hello, World!');      writeln(format('y : %d', [y]));    end; begin  main;end. Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i $ fpc main.pas Free Pascal Compiler version 3.3.1 [2022/11/19] for x86_64Copyright (c) 1993-2022 by Florian Klaempfl and othersTarget OS: Linux for x86-64Compiling main.pasLinking main45 lines compiled, 0.2 sec, 375712 bytes code, 167784 bytes dataSat 19Nov22 15:16:11 /home/dev/das_misc/sandbox-scratch/defer $ ./main Hello, World!y : 4Goodbye World! y = 5Last added runs first! y=5First added runs last! y=5  So if someone is looking for something akin to defer from other languages: https://github.com/vlang/v/blob/master/doc/docs.md#defer https://golangbot.com/defer/ that can be approximated in Free Pascal. (By either providing a function to defer or code to defer execution of, then the above code demonstrates how that can be done). ---------------------------------------------------------------------- PascalDragon · 2022-11-19 21:48 Please note that FPC does in no way guarantee when exactly a managed type is finalized. It can be at the end of the function (line 38 of your example program) or directly after its last use (between line 35 and 36 of the example program). It's only guaranteed that it's finalized at the latest at the end of the scope. ---------------------------------------------------------------------- Bogen85 · 2022-11-19 22:08 Quote from: PascalDragon on November 19, 2022, 10:48:23 pmPlease note that FPC does in no way guarantee when exactly a managed type is finalized. It can be at the end of the function (line 38 of your example program) or directly after its last use (between line 35 and 36 of the example program). It's only guaranteed that it's finalized at the latest at the end of the scope. Understood. So from what I understand an empty placeholder method could be added to the defer managed type, to anchor the calls to the bottom of the scope. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ...  public    property x: tDeferProc write assign;    procedure anchor;  end; implementation procedure tDefer.anchor;  begin  end;...  And when used: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i begin  ...  defer.anchor; // placed right before final end;end; ---------------------------------------------------------------------- Bogen85 · 2022-11-19 22:46 Quote from: PascalDragon on November 19, 2022, 10:48:23 pmPlease note that FPC does in no way guarantee when exactly a managed type is finalized. It can be at the end of the function (line 38 of your example program) or directly after its last use (between line 35 and 36 of the example program). It's only guaranteed that it's finalized at the latest at the end of the scope. Thanks for pointing that out! Same here: Quote from: AlexTP on June 27, 2021, 01:29:35 pm@PascalDragon, Offtopic: I am your fan, trying to read all your last messages. ---------------------------------------------------------------------- PascalDragon · 2022-11-19 23:12 Quote from: Bogen85 on November 19, 2022, 11:08:14 pmQuote from: PascalDragon on November 19, 2022, 10:48:23 pmPlease note that FPC does in no way guarantee when exactly a managed type is finalized. It can be at the end of the function (line 38 of your example program) or directly after its last use (between line 35 and 36 of the example program). It's only guaranteed that it's finalized at the latest at the end of the scope. Understood. So from what I understand an empty placeholder method could be added to the defer managed type, to anchor the calls to the bottom of the scope. Yes, that would work. Also an additional remark for your code: the Initialize operator is not required, because dynamic arrays are always initialized to an empty array anyway. ---------------------------------------------------------------------- Bogen85 · 2022-11-19 23:17 Quote from: PascalDragon on November 20, 2022, 12:12:23 amYes, that would work. Thanks for clarification. Quote from: PascalDragon on November 20, 2022, 12:12:23 amAlso an additional remark for your code: the Initialize operator is not required, because dynamic arrays are always initialized to an empty array anyway. Thanks as well! ---------------------------------------------------------------------- Bogen85 · 2022-11-20 00:03 I created https://github.com/bogen85/fpc-defer for this. ---------------------------------------------------------------------- Thaddy · 2022-11-20 08:31 Note that is it is not a good idea to name your unit defer and subsequently in main a variable that is also called defer, while also having a defer in the uses clause. I would change the unit name in this case, suggest fpcdefer, deferrer or something. It is not knit-picking. Such name clashes can bite. But it is very neat code, may come in useful. ---------------------------------------------------------------------- Bogen85 · 2022-11-20 08:51 Quote from: Thaddy on November 20, 2022, 09:31:38 amNote that is it is not a good idea to name your unit defer and subsequently in main a variable that is also called defer, while also having a defer in the uses clause. I would change the unit name in this case, suggest fpcdefer, deferrer or something. I made the unit name change, from defer to fpcdefer. Quote from: Thaddy on November 20, 2022, 09:31:38 amIt is not knit- picking. Such name clashes can bite. Agreed. I appreciate the feedback. Quote from: Thaddy on November 20, 2022, 09:31:38 amBut it is very neat code, may come in useful. Thanks! ---------------------------------------------------------------------- AlexTP · 2022-11-20 09:32 @bogen85 Why to add 'property x', better to add 'procedure Add'. ---------------------------------------------------------------------- Bogen85 · 2022-11-20 10:41 Quote from: AlexTP on November 20, 2022, 10:32:59 am@bogen85 Why to add 'property x', better to add 'procedure Add'. I see your point. However defer.x := some code means defer execution of some code In other languages defer is a keyword meaning that, and this is meant to approximate how it is used elsewhere. I can see how for some defer.add(some code) makes more sense. I'll keep x  but I changed assign to add and made it public. I updated my example.