Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 05:12 10 Nov 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : [MMBASIC] Proposal to add STATIC keyword

Author Message
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 06:57am 01 Sep 2015
Copy link to clipboard 
Print this post

While programming i noticed that i often use a lot of global variables out of necessity.
This gets out of hand quickly and also makes it more difficult to make library functions.
At the moment i use the LibraryName.VariableName notation and that works ok but still everything ends up in the global variable space where it preferably would not.

I would like to suggest the STATIC keyword that can be used instead of LOCAL, or as a modifier for the LOCAL keyword.
When making subroutines and functions LOCAL will reinitialize on every entry.
This is great but having the possibility of variables not loosing their value between calls would be very very nice to have.

Especially when using timers or interrupts, variables can stay local.

I can think of two ways how to use the STATIC keyword.
Just by itself:
[code]
SUB MySub
STATIC INTEGER MyVariable
END SUB
[/code]
or as a modifier:
[code]
SUB MySub
STATIC LOCAL INTEGER MyVariable
'or
LOCAL STATIC INTEGER MyVariable
END SUB
[/code]

Having STATIC variables will also increase speed and efficiency as not on every call variables have to be initialized and allocated (this i don't know, could be that it is reserved the first time and then reused)


What do you think?

Edited by TZAdvantage 2015-09-02
Microblocks. Build with logic.
 
Dylan
Regular Member

Joined: 17/06/2013
Location: Netherlands
Posts: 81
Posted: 06:08am 03 Sep 2015
Copy link to clipboard 
Print this post

The problem is that BASIC is interpreted. This means that global variables get assigned space on the heap when first declared, but local variables are assigned on the stack.

So what you are really looking for is global variables that are hidden to functions other than the one you want it to seem local to.

https://en.wikipedia.org/wiki/Name_mangling comes to mind. Your STATIC needs some sort of way to add it to the global symbol table in such a way that only the subroutine it was declared in.
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 07:03am 03 Sep 2015
Copy link to clipboard 
Print this post

If i remember correctly Geoff optimized the use of Functions and Subroutines.
When a program is first run it makes a list of all functions and subroutines so that a lookup is much faster. In that optimize step, variables that are static could be added. This would again make programs run much faster as allocating and initializing does not have to happen on each call.
When using interrupts routines which are normally very short this could make a real difference.

So it is not only to keep the global variable space cleaner, which is a really good reason by itself. But also squeezing every bit of performance out of it.:)

The reason for LOCAL variables to be on the stack is for multiple entry scenarios, which for a STATIC is not a problem.
Edited by TZAdvantage 2015-09-04
Microblocks. Build with logic.
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 4126
Posted: 08:30am 03 Sep 2015
Copy link to clipboard 
Print this post

For now you may as well just use, in function MyFunc, names like MyFunc.MyVar1

That saves yet another language feature and works immediately.

John
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 08:35am 03 Sep 2015
Copy link to clipboard 
Print this post

That is exactly what i do and it is the exact reason why i proposed this. :)

I do not know where 'saving' comes from.
Improvements should always be considered.

Microblocks. Build with logic.
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 4126
Posted: 09:23am 03 Sep 2015
Copy link to clipboard 
Print this post

Every added feature adds memory. By not adding them you save memory.

John
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 10:03am 03 Sep 2015
Copy link to clipboard 
Print this post

The form MyLibrary.MyVariable uses a lot of memory too. Each variable having a prefix, just to keep the global variables understandable and make sure variables from different libraries do not clash.
I would prefer short and static variables right where it is needed.
Namespacing is a good thing when you can specify the namespace only once. Not a simulation of one.
I think that is a lot harder to implement though.

Functions/Subroutine within functions/subroutine would also work.
You could then have a single routine that contains everything needed for that functionality. But that gets close to multitasking, which actually might be easier to implement.

Another way would be to just create a array of bytes and instead of variables just use locations to hold the values. Like a struct/union in C, but without the luxury of using variable names.





Edited by TZAdvantage 2015-09-04
Microblocks. Build with logic.
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3308
Posted: 11:41pm 03 Sep 2015
Copy link to clipboard 
Print this post

Sorry everyone, I missed this thread while I was away (matherp has just alerted me to it).

It should be easy to do and I will add it to the ToDo list (currently 41 items and counting).

I am not sure about a functions/subroutine within a functions/subroutine. I tried implementing it once and my brain had a meltdown !!

Geoff
Geoff Graham - http://geoffg.net
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 01:01am 04 Sep 2015
Copy link to clipboard 
Print this post

That's great Geoff!

I was thinking about how functions/subroutines could be reused and one way would be to use a 'callback' mechanism. This will allow reuse of functions and 'chaining' and also reduces the amounts of global variables.

All the parts are in place i think.
As an example a sort routine.
Some MMBAsic style code.
[code]
DIM INTEGER D(100)
DIM STRING S(100)

Sort D(), MyIntegerCompare
Sort S(), MyStringCompare

SUB Sort(values, FnCompare)
'Implement a sort algorithm
'When it is time to compare values use
SELECT CASE FnCompare(values(index), values(index+1))
CASE -1
CASE 0
CASE 1
END SELECT
'etc...
END SUB

FUNCTION MyIntegerCompare(a, b)
IF a < b THEN
MyIntegerCompare = -1
ELSEIF a > b THEN
MyIntegerCompare = 1
ELSE
MyIntegerCompare = 0
ENDIF
END FUNCTION

FUNCTION MyStringCompare(a, b)
LOCAL aup = UCASE$(a), bup = UCASE$(b)
IF aup < bup THEN
MySortCompare = -1
ELSEIF aup > bup THEN
MySortCompare = 1
ELSE
MySortCompare = 0
ENDIF
END FUNCTION
[/code]
That's as close to anonymous function and generics as you can get with basic, without changing the whole language.

Function within function can be done by using a extra variable, but can only be done when Temp is STATIC or a Global variable.
[code]

PRINT MyFunction 1,2

FUNCTION MyFunction(var1, var2, sel)
CONST FIRSTFUNCTION = 1, SECONDFUNCTION = 2
LOCAL STATIC Temp = 0

SELECT CASE sel
CASE FIRSTFUNCTION
Temp = MyFunction(var1 * var2, var2 * 6, SECONDFUNCTION)
CASE SECONDFUNCTION
MyFunction = Temp + var1 ^ 2
END SELECT
END FUNCTION
[/code]
Javascript saves the whole context and values of the variables. But that can only be done when memory is cheap and abundant. BASIC is a much better match for a mcu same like C as it is still pretty close to the metal although it not always seems that way.
What could be done to make the above a bit less ugly is the following:
[code]
FUNCTION MyFunction(var1, var2)

MyFunction = FirstFunction(var1,var2) + SecondFunction(var1)

FUNCTION FirstFunction(var1,var2)
FirstFunction = SecondFunction(var1 * var2, var2 * 6)
END FUNCTION

FUNCTION SecondFunction(var1,var2)
SecondFunction = var1 ^ 2
END FUNCTION

END FUNCTION
[/code]
But this is looking more difficult to parse and execute.
It looks a lot cleaner though and uses less variables.

If it can be done though then the next step comes very close and that is to be able to do
[code]
MyFunction.FirstFunction(1,2)
[/code]

This would then make it possible to make a library function contained in a single function. That would work great in combination with LIBRARY.

I'll shutup now. :)



Edited by TZAdvantage 2015-09-05
Microblocks. Build with logic.
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3308
Posted: 03:36am 04 Sep 2015
Copy link to clipboard 
Print this post

TZ: I think that I can see what you are trying to do with the first example and it is definitely worth investigating. It involves pointers to functions in BASIC... I can feel another brain meltdown coming on.
Geoff Graham - http://geoffg.net
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 03:45am 04 Sep 2015
Copy link to clipboard 
Print this post

Yes, similar to what now is used when setting up a SETTICK or interrupt on a pin.
A subroutine name is then also passed by reference.
From a syntax/parsing point of view it is already done before and seems to be a good fit for the language.
I realize that the execution of that will be a lot more complicated.
Just throwing out some ideas.

Microblocks. Build with logic.
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3308
Posted: 12:30pm 02 Oct 2015
Copy link to clipboard 
Print this post

I have recently investigated this idea and I am sorry to say that it is not possible with the current MMBasic structure.

When a variable is created it is given a "level" qualifier. If "level" is zero it means that the variable is global otherwise the variable is LOCAL and the number indicates the depth in the subroutine stack that the variable applies to. When a program exits up the subroutine stack this context is lost so STATIC cannot be used.

I will look at other ways of managing the variable table but the current method has the advantage of being fast and economical (in terms of code space). Rather than engaging in a major rewrite I will tackle other improvements first.

Geoff
Geoff Graham - http://geoffg.net
 
DavidSG
Newbie

Joined: 16/07/2017
Location: Australia
Posts: 8
Posted: 02:24am 16 Jul 2017
Copy link to clipboard 
Print this post

I'm a latecomer to this party - only just got a Micromite going for the first time this morning. I went looking for STATIC and wound up on this page. I can understand why it's too hard in an interpreter.

A comment on local functions inside functions. For many years I used local GoSubs inside real subroutines and functions in Visual Basic (3 and 6). Some might consider that ugly. I found it very useful for encapsulating a bunch of functionality inside a Sub/Func. It's like having an object instance without proper OOP, especially if you also have static locals. With arrays you could get something akin to classes, though I've never had to go that far.

I like to use finite state machines a lot. Local GoSubs are especially useful for coding state transition actions just once then calling them from several places, rather than having the same lump of code replicated multiple times. They do not need formal parameters to be useful, so there need be no stack implications other than a return address and perhaps a nesting counter.
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025