Page 1 of 1

defer test

Posted: Wed Sep 11, 2024 5:43 pm
by chi
Found this defer macro and played around a little bit. It's very restricted (in PB), cumbersome and verbose (.c file), but somehow works...

Code: Select all

CompilerIf #PB_Compiler_Backend <> #PB_Backend_C  
  CompilerError "'defer test' needs the C backend (GCC only)"
CompilerEndIf

Macro defer_Pb(func)
! #undef CAT_
! #undef CAT
! #undef defer

! #define CAT_(a, b) a ## b
! #define CAT(a, b) CAT_(a, b)

! #define defer                                                                               \
!     auto void CAT(DEFER_FUNCTION_, __LINE__)(int *);                                        \
!     int CAT(DEFER_VAR_, __LINE__) __attribute__((cleanup(CAT(DEFER_FUNCTION_, __LINE__)))); \
!     void CAT(DEFER_FUNCTION_, __LINE__)(int *)  

! defer { PB_#func; }
EndMacro

Macro defer_My(func)
! #undef CAT_
! #undef CAT
! #undef defer

! #define CAT_(a, b) a ## b
! #define CAT(a, b) CAT_(a, b)

! #define defer                                                                               \
!     auto void CAT(DEFER_FUNCTION_, __LINE__)(int *);                                        \
!     int CAT(DEFER_VAR_, __LINE__) __attribute__((cleanup(CAT(DEFER_FUNCTION_, __LINE__)))); \
!     void CAT(DEFER_FUNCTION_, __LINE__)(int *)  

! defer { f_#func; }
EndMacro

Procedure My_Print(txt$)
  PrintN(txt$)
EndProcedure

Procedure Run()
  defer_Pb(PrintN(L"\npress any key to continue..."))     ;;; L"" needed to output wide-character strings 
  My_Print(~"defer test:\n")                              ;;; if ommited, calling next line: defer_My(my_print(..)) = unresolved external symbol
  defer_My(my_print(L"\nexpected output: 1, 3, 4, 6, 5, 2")) ;;; my_print must be lower case...
  
  PrintN(" 1 ")  
  defer_Pb(PrintN(L" 2 "))
  PrintN(" 3 ")  
  PrintN(" 4 ")
  defer_Pb(PrintN(L" 5 ")) 
  PrintN(" 6 ") 
EndProcedure

OpenConsole()
defer_My(my_print(L"not working in PB's main scope"))
Run()
Input()

Re: defer test

Posted: Wed Sep 11, 2024 8:05 pm
by NicTheQuick
Can you please explain what this actually does?

Re: defer test

Posted: Wed Sep 11, 2024 11:48 pm
by spikey
Some languages, like Go, define a defer function which allows an operation to be stated at one point in code but defers the execution of said operation until the enclosing procedure ends. The idea is to protect against something like this:

Code: Select all

Procedure Something()
  *Buffer = AllocateMemory(2000)
  
  ; do something complicated with memory
  ; ...
  If Complicated Code doesn't work 
    ProcedureReturn
  Else
    ; do something else here.
  EndIf
  
  FreeMemory(*Buffer)  
  
EndProcedure
In this case, if "Complicated Code" doesn't work the procedure returns without freeing the memory, leading to a leak.

In these languages, you can write something similar to:

Code: Select all

Procedure Something()
  *Buffer = AllocateMemory(2000)
  Defer(FreeMemory(*Buffer))
  
  ; do something complicated with memory
  ; ...
  If Complicated Code doesn't work 
    ProcedureReturn
  Else
    ; do something else here.
  EndIf
  
EndProcedure
The compiler will automatically handle deferred operations regardless of where they appeared in the source and the actual exit point in the procedure. The theory says it should lead to fewer bugs because allocation and deallocation code can always be adjacent in the source code but effective at the exit point in the object code. There is less likelihood of something being forgotten by a fallible programmer or a future code change breaking something accidentally because something was overlooked.

There is a more comprehensive explanation at https://www.digitalocean.com/community/ ... efer-in-go.

Re: defer test

Posted: Thu Sep 12, 2024 1:01 am
by jacdelad
Like a Try...Error...Finally?

Re: defer test

Posted: Thu Sep 12, 2024 9:13 am
by chi
spikey already nailed it with the description... thx ;)

Re: defer test

Posted: Thu Sep 12, 2024 12:06 pm
by NicTheQuick
Thanks for the clarification. That sounds really cool.

I am however a big fan of proper exception handling. A try..catch..finally construct would be much appreciated but I fear Purebasic will never get this functionality.

Re: defer test

Posted: Wed Oct 02, 2024 6:59 am
by fsw
Some other languages offera defer that is executed when a scope ends (any scope, not only procedures).