[Gambas-user] Correct strategy for VB static var conversion to Gambas?

John Anderson johna at starflightinc.com
Mon May 31 01:40:49 CEST 2021

On 5/30/2021 11:43 AM, Christof Thalhofer wrote:
> Am 30.05.21 um 18:55 schrieb John Anderson:
>> On 5/29/2021 3:50 PM, Christof Thalhofer wrote:
>>> Am 29.05.21 um 22:09 schrieb Benoît Minisini:
>>>> So maybe I could allow declaring "static variables" (actually private
>>>> global class variables) inside functions in the future.
>>> That would make code even uglier. Is there any reason to do this that
>>> makes sense?
>>> Alles Gute
>>> Christof Thalhofer
>> Thanks, I understand your concern...and it is not my intention that my
>> needs require Gamabs to break anything it currently does well.
>> Let me explain the situation more.  Warning - this is long, but only way
>> I know of to explain.  If your time is short please just skip the rest.
>> The following ONLY applies to VB conversion project.
>> Well, in order to implement the equivalent of a "Static" var in a
>> function, and since a lot of our functions use common names as
>> "mystaticvar" in lots of functions: the only way I know of is to make a
>> separate module for each function.
> Ok, now I think I understand. Maybe it was a misunderstanding by me, I
> thought you wanted to be able to define *Global* Static Variables inside
> functions (I mean global accessible). I think I did not read carefully
> enough.
> As I now understand you want to have variables that reside inside
> methods that keep their value from call to call.
> This undermines what I think is an important security aspect of Gambas,
> which is that methods in classes are stateless unless they use global
> variables of the class. Programmers who are not that experienced might
> be misled by the name "static". Readers of code could easily overread
> that a variable is not stateless any more.
> Gambas actually has a pretty clean design, I'm unsure if it will be
> compromised by this idea. I'm afraid it will be.
> There is an agreement that Gambas programmers use the prefix "$" for
> variable names to indicate a global variable of a class. Actually, if
> your idea were implemented, one would have to consider that static
> variables within methods get their own prefix to identify them and a
> common agreement to use that.
> I did not read your long mail to the end, maybe there will be more
> arguments from my side.
> Alles Gute
> Christof Thalhofer
I don't blame you for not reading the whole thing...<Grin>

Correct - We have to have a way so that each module function can have a 
"static" variable that has scope of just that one function only, and the 
value persists across each function call.  Exactly how static vars work. 
Just like a local, except initialized only at first function call, and 
they are stored in system static heap, not the stack.

Yes, we could put a lot of functions (aka methods) into a module, but 
we'd have the problem of defining the "static" variables in the 
declarations section.  Which is OK, except the functions have a lot of 
same static names -  Now we have to come up with new names for the 
statics used in each function contained in the module, and we need to 
avoid that if at all possible.

My solution is to put one function per module file, with its statics in 
declaration area.

This might help to understand what we do now - and we really want to try 
to retain as much valuable source code as possible.  Tested and Known 
Working Logic path = Priceless.

don't need to be told how it coulda/shoulda been done differently. It's 
what I have to work with...some 84,000 lines.  And no, we aren't going 
to re-write everything if we can avoid it.  Currently everything runs 

As a concept - This is what we have now in VB code - and we have many 
hundreds of these function sequences that operate as state machines, and 
can be called from other state machines above them. The main top level 
state machine timing loop is at level zero, and that's where E-Stop and 
safety checks are done, and that loop has control over all state 
machines operating below it.  When the operator hits "Start Some 
Function" button, we start working thru the state machine sequences 
according to a large config file system etc.   The top level Main loop 
fires every few mSec. and the Main Loop can start falling into various 
state machine functions as required.

This is a typical part of a system loop that is fired every few mSec by 
master control code timing loop.  Every state in the state machine must 
be non-blocking, and these are typically short function calls to C-code 
for motion control system, machine vision, etc.

Public SeqFuncA (SeqLevel as Int, Some Parameters list) as Boolean

         Dim x as Integer  ' A regular local variable, and initialized 
at every call
         Static StaticLoopCount  as Long - A static that retains it's 
value at every function call
         Static myTimer as New clsOurTimer   ' Our own Timer class object
         Static XYZPositionStart as new clsPoint 'Our own position 
storage class that holds position of machine motors at the start of this 
         Static mySeqArray(0 to 2000)  as Long    'We use arrays for a 
lot of C code calls

         'State machine start
         Select Case ucStateControl(SeqLevel).State   ' This is our 
master User State Control that tells us what state were in for each 
sequence level, starts at zero every time a new SeqLevel is started 
Available Globally to all functions.

Case 0
         'Do Something like initialize vars at first state
         myStaticLoopCount =0
         GetMachineMotorPositions( ByRef XYZPositionStart) ' Store 
current positions of all motors
         ucStateControl(SeqLevel).NextState = 10  'The next time we drop 
into this function we will be at State 10

Case 10
         AirValve(1).SetOn         'AirValve #1 is turned on now
         myTimer.Set = 50        'Wait 50 mSec at next case to allow air 
cylinder retract
         ucStateControl(SeqLevel).NextState = 20  'The next time we drop 
into this function we will be at State 20

Case 20
         if myTimer.isDone and LaserSafeFlag.isSafe then     'We don't 
advance to next state until timer don and lasersafe say it is OK to proceed.
             ucStateControl(SeqLevel).NextState = 30
         end if

Case 30
      myStaticLoopCount =  myStaticLoopCount + 1  ' Keep track of how 
many times we've hit this state
      '...More states

     ucStateControl(SeqLevel).NextState = 500

Case 500
     if SomethingWasNotCorrectCondition
         MasterSeqErrorCode = AnErrorCode         'Global
         SeqFuncA=True  'Signal to calling process we are completed, and 
error code will be thrown to show there was a problem
             ucStateControl(SeqLevel).NextState = 510
      end if

Case 510
     'More states if no error

Case 990
       if myStaticLoopCount > CurrentRecipe.TargetRepeatLoops.Value  
then        'Recipe class is available globally, and provides options to 
state machines
             ucStateControl(SeqLevel).NextState = 1000   ' Get ready to 
finish state machine at next state depending on myStaticVar
              ucStateControl(SeqLevel).NextState = 30   ' Repeat steps 
until loops completed
     end if

Case 1000
     AirValve(1).SetOff         'AirValve #1 is turned off now
     MoveMotorsXYZ(XYZPositionStart)  'Start moving all motors back to 
start position.
     ucStateControl(SeqLevel).NextState = 1100

Case 1100
     If isAllMotorsStoppedFlag then            'Global Safety Flag to 
make certain all motors are stopped moving before sequence is completed
         SeqFuncA=True  'Signal to calling process we are completed, 
MasterSeqError flag will be False
     end if

End SeqFuncA

Somewhere else in a sequence loop at a sequence level above this - we 
start the above sequence with

Case XXX
If SeqFuncA(SeqLev+1, SomeParametersList)

     'See if error occured
     if MasterSeqErrorCode then
         'Do something here if there was a problem with that sequence, 
MasterSeqErrorCode stays set
         SeqHigherLevelFunc = True    ' Now this sequence will exit to 
next higher level sequence
     end if

     ucStateControl(SeqLevel).NextState = YYY ' Go to next state of this 

end if

So that's what I'm attempting to convert with Gambas.  And a "Static" 
var type inside a function / module method would help a lot.


More information about the User mailing list