Page 1 of 1

Using/With/Try&Finally/... or similar

Posted: Mon May 01, 2017 6:59 am
by DarkDragon
Hello,

As we currently discuss the Try/Catch, there is a very connected keyword in other languages that I would suggest for PureBasic. In C# it is Using, in python it is With. If we cannot have Try/Catch, we may still have a kind of centralized clean up inside of scopes.

It looks like this:

Code: Select all

Using *Buffer[ = AllocateMemory(...)]
  ; use buffer
EndUsing
it is equal to

Code: Select all

[*Buffer = AllocateMemory(...)]
Try
  ; use buffer
Finally
  ; Clean up the object
  FreeMemory(*Buffer)
EndTry
So when leaving the scope, the buffer will be released automatically. In situations similar to the following two two it is useful, otherwise you'd have to care about cleaning up resources inside the If-blocks in this scope every single time:

Code: Select all

; Situation 1
Procedure Whatever()
  Using *Buffer
    ...
    If something
      ...
      ProcedureReturn ...
    EndIf
    ...
    If something
      ...
      ProcedureReturn ...
    EndIf
    ...
  EndUsing
EndProcedure

; Situation 2
For i = 0 To 20
  Using *Buffer
    ...
    If something
      ...
      Break
    EndIf
    ...
    If something else
      ...
      Continue
    EndIf
    ...
  EndUsing
Next
However, the FreeMemory is somewhat too static, so a kind of destructor should be called instead. As PureBasic is not object oriented so much, a destructor call for each object would be kind of inconsistent and you may need to access variables of the outer scope anyway during cleanup. So I would prefer the Finally construct instead, even if Catch may not be implemented (in the near future).

Re: Using/With/Try&Finally/... or similar

Posted: Mon May 01, 2017 12:00 pm
by Sicro
+1

Without a native solution is probably not much more possible than that:

Code: Select all

Macro CleanUp(_Object_)
  
  If IsGadget(_Object_)   : FreeGadget(_Object)
  ElseIf IsFile(_Object_) : CloseFile(_Object_)
  ElseIf IsFont(_Object_) : FreeFont(_Object_)
  ElseIf _Object_ > 0     : FreeMemory(_Object_)
  EndIf
  
EndMacro


Macro Using(_Object1_=-1, _Object2_=-1, _Object3_=-1, _Object4_=-1, _Object5_=-1, _Object6_=-1, _Object7_=-1)
  
  CompilerIf Not Defined(ObjectsCollector, #PB_List)
    NewList ObjectsCollector()
  CompilerEndIf
  
  If _Object1_ <> -1
    AddElement(ObjectsCollector())
    ObjectsCollector() = _Object1_
  EndIf
  
  If _Object2_ <> -1
    AddElement(ObjectsCollector())
    ObjectsCollector() = _Object2_
  EndIf
  
  If _Object3_ <> -1
    AddElement(ObjectsCollector())
    ObjectsCollector() = _Object3_
  EndIf
  
  If _Object4_ <> -1
    AddElement(ObjectsCollector())
    ObjectsCollector() = _Object4_
  EndIf
  
  If _Object5_ <> -1
    AddElement(ObjectsCollector())
    ObjectsCollector() = _Object5_
  EndIf
  
  If _Object6_ <> -1
    AddElement(ObjectsCollector())
    ObjectsCollector() = _Object6_
  EndIf
  
  If _Object7_ <> -1
    AddElement(ObjectsCollector())
    ObjectsCollector() = _Object7_
  EndIf
  
EndMacro


Macro EndUsing
  ForEach ObjectsCollector()
    CleanUp(ObjectsCollector())
  Next
EndMacro


File    = CreateFile(#PB_Any, GetTemporaryDirectory() + "Temp")
Font    = LoadFont(#PB_Any, "Arial", 12)
*Memory = AllocateMemory(1024)

Debug "--- Before using ---"
Debug "File:   " + IsFile(File)
Debug "Font:   " + IsFont(Font)
Debug "Memory: " + PeekB(*Memory)

Using(File, Font, *Memory)
  ; ...
  ; Do something
  ; ...
EndUsing

Debug ""
Debug "--- After using ---"
Debug "File:   " + IsFile(File)
Debug "Font:   " + IsFont(Font)
Debug "Memory: " + PeekB(*Memory)

Re: Using/With/Try&Finally/... or similar

Posted: Mon May 01, 2017 1:01 pm
by Zebuddi123
Hi to All. I think Macro`s in general are a Penicillin of Antibiotics and I really like these little brain teasers, Although I not so good I do like trying to solve the problem/s and it takes far more thought and analysis than Procedures. Give you another way of thinking. @Sirco I like your solution Gone straight into my templates :)

Zebuddi. :)

Re: Using/With/Try&Finally/... or similar

Posted: Mon May 01, 2017 1:51 pm
by DarkDragon
Sicro wrote:Without a native solution is probably not much more possible than that[...]
Yes exactly, we cannot even ensure that it is being executed when we leave the scope. So EndUsing always has to be reached in your code, which is not the sense of it. Put a ProcedureReturn, Break, Continue, ... inside and EndUsing won't be executed.