[Gambas-user] Correct strategy for VB static var conversion to Gambas?
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
> 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
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.
WARNING - THE FOLLOWING CODE SAMPLE MAY BURN if you're squeamish. I
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.
'Do Something like initialize vars at first state
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
AirValve(1).SetOn 'AirValve #1 is turned on now
myTimer.Set = 50 'Wait 50 mSec at next case to allow air
ucStateControl(SeqLevel).NextState = 20 'The next time we drop
into this function we will be at State 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
myStaticLoopCount = myStaticLoopCount + 1 ' Keep track of how
many times we've hit this state
ucStateControl(SeqLevel).NextState = 500
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
'More states if no error
if myStaticLoopCount > CurrentRecipe.TargetRepeatLoops.Value
then 'Recipe class is available globally, and provides options to
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
AirValve(1).SetOff 'AirValve #1 is turned off now
MoveMotorsXYZ(XYZPositionStart) 'Start moving all motors back to
ucStateControl(SeqLevel).NextState = 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
Somewhere else in a sequence loop at a sequence level above this - we
start the above sequence with
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
ucStateControl(SeqLevel).NextState = YYY ' Go to next state of this
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