[Solved] Long live the static variable!

Creating a macro - Writing a Script - Using the API (OpenOffice Basic, Python, BeanShell, JavaScript)
Post Reply
jrgsampaio
Posts: 5
Joined: Fri Aug 07, 2026 9:15 am

[Solved] Long live the static variable!

Post by jrgsampaio »

Hi all...
This is not an issue but rather a solution, who some may need someday.
LO macro, and many other versions, dialects and similars, has a statement to declare variables and arrays called "STATIC". It can be used in a procedure level (subs and functions), but they cannot be declared outside them. When a variable is delcared as STATIC (instead of using DIM or REDIM) the value attributed to it in a call to the procedure is retained for as long as the envorinment is running.

However, if a procedure is invoked from a document, say a Calc document, as a user defined function and not by a running program, the static variable DIES after the procedure exits, returning to the calling document. A next call to the same procedure will not get the value saved to the static variable. For example:

Code: Select all

function testatic(x as double) as double
    static stCount as long
    stCount = stCount + 1
    testatic = x * stCount
end function
In this dumb code, a static variable (a counter) is declared as a static integer (and gets the value 0).
If the function is called for the first time from calc, passing a value say 8, as the sole argument...

(from a calc cell:) [ =testatic(8) ] (enter) ... (the [...] is just to simulate a cell, not to be typed in in...; the same to (enter)...)

... it is expected that the code will run, increment the static value to 1, multiply 8 by 1 and return the value (testatid=) 1*8.
If the the procedure is called again from calc, for example passing the argument 5, one expects that the static variable stCount will increment to 2, and the function will return 2*5 = 10. Surprisingly (or not so), it returns 5, that is the static variable lost the expected saved value "1" and returned to the value 0, which is incremented to 1, then multiplied by 5 returning 5 again, not 10.

I have a problem that requires to evaluate a computational costly function using path integral along a long trajectory starting in at x=0 (it doesn't matter...(*) ). The calc document will call the function many, many times at values of x that vary about (and eventually converge to) the solution which, and for every call, it has to start the integration from zero, so that the best strategy is it to keep the last values of x, and all internal values (the reason of make them STATIC) and use them as the starting point to calculate the function at the new x. Just to give an idea of the cost/time in a run, the calc process took 2 hours to conclude.

I searched around and could't find anything similar that could resolve the issue (except to code the whole problem as a macro, but I would loose all the control I have on the run, and for that I wouldn't need calc).
I realized that I needed to keep the environment runing between calls, so that the static variable would remain "alive". Then I coded a dumb subroutine to start a do-wait-loop process. Here a simplified version of the sub:

Code: Select all

sub foreverloop ()
    do
        wait 10000  ' 10 seconds 
         beep           ' just to tell me it's running
    loop
end sub
After putting to run try in calc... [ =testatic(8) ] (or 5, 3, 1234...) and the stCount will keep there. Then stop the foreverloop() and try ot again.

I was concerned about the overhead that an not-ending loop with a wait would put on the cpu, but I found some sources saying that the wait statement just use internal circuitry clock (that is always ticking) and the overhead is negligible (maybe infinitesimal) compared to all processes that are already running in the machine (which is far from few) even without any user load.

The subroutine is put to run before starting the process in calc, and after conclusion the dumb function is stopped.
Surprisingly (or not so), it workd prefectly! The same process above that took 2 hours to conclude finished in ... 120 seconds.

If somebody has a better or more efficient solution, please let me know. If no other solution exist, it would be interesting that adequate solution could be implemented by the the macro developed team.
Jorge

(*) for those interested, the process involve an adaptive 5th-order Runge-Kutta algorithm to path integrate 9 differential equations that define 9 generalized hypergeometric functions evaluated at (-x^3)/9 for values of x somewhere between 30 and 100+...)
Last edited by MrProgrammer on Sun Sep 13, 2026 9:08 pm, edited 3 times in total.
Reason: Tagged ✓ [Solved]
LibreOffice 26.2 on Ubuntu 26.04
User avatar
Zizi64
Volunteer
Posts: 11511
Joined: Wed May 26, 2010 7:55 am
Location: Budapest, Hungary

Re: Long live the ... static variable!

Post by Zizi64 »

Tibor Kovacs, Hungary; LO7.5.8/25.8.5.2 /Win7-10-11 x64Prof.
PortableApps: LO3.3.0-25.8.5.2;AOO4.1.14
Please, edit the initial post in the topic: add the word [Solved] at the beginning of the subject line - if your problem has been solved.
jrgsampaio
Posts: 5
Joined: Fri Aug 07, 2026 9:15 am

Re: Long live the ... static variable!

Post by jrgsampaio »

You know well, and I know too.
The only one that would do the job is Global (it is similar to Static but too exposed), but I need to keep retaining variables local for each function. I have 9 functions with many variables and arrays of various ranks which must be kept between calls. Using global to define the variables exposes them to be altered by other calls and the reults will be unpredictable.

They need to be local, and to be retained the macro must be kept running. A call to a function from Calc (for example using a macro function =foo(<list of args>) from any cell starts the macro, executes the function, and after return to Calc the macro stops, and ALL static defined variables of the called procedure are lost. That's why I need STATIC variable, the subject of the post.

Run the example that I put and try yourself, then tell what you've found. Here is it again:

Code: Select all

function testatic(x as double) as double
    static stCount as long 
    stCount = stCount + 1
        testatic = x * stCount
end function
PLease, do not be limited to this simple example; it is just... an example to understand the limitation.

Call the function from Calc and see if the static variable is retained or not. Put, say 5 in cell A2 ans in cell A1 add "=testatic(B1)". Now, change the value in B1 to any other number, and see if the countet stCount will do it work or not. You will find that it is NOT. You must keep the macro environment running.

Now add this little loop to the module ...

Code: Select all

sub foreverloop ()
    do
        wait 10000	' 10 seconds per loop without demanding CPU
    loop
end sub
Run it, go back to Calc, and repeat the call to the and you see the result. Then stop the looping, and do it again. You will see that the results are completely different.
Jorge
Last edited by jrgsampaio on Sun Aug 09, 2026 9:29 am, edited 2 times in total.
LibreOffice 26.2 on Ubuntu 26.04
User avatar
robleyd
Moderator
Posts: 5528
Joined: Mon Aug 19, 2013 3:47 am
Location: Murbko, Australia

Re: Long live the ... static variable!

Post by robleyd »

You can format code by using the </> icon, or use [code]....[/code] tags in your post.
Slackware 15 (current) 64 bit
Apache OpenOffice.1.16
LibreOffice 26.8.0.3; SlackBuild for 26.8.0 by Eric Hameleers
-----------
I hate this damn computer, I wish that I could sell it.
It won't do what I want it to, Only what I tell it.
jrgsampaio
Posts: 5
Joined: Fri Aug 07, 2026 9:15 am

Re: Long live the ... static variable!

Post by jrgsampaio »

Thanks, I am new here. Now it uses the

Code: Select all

. Thanks.
LibreOffice 26.2 on Ubuntu 26.04
Bidouille
Volunteer
Posts: 700
Joined: Mon Nov 19, 2007 10:58 am
Location: France

Re: Long live the ... static variable!

Post by Bidouille »

Forget about Basic.
The best way to have your own functions in Calc is to use Python language.
User avatar
Lupp
Volunteer
Posts: 3761
Joined: Sat May 31, 2014 7:05 pm
Location: München, Germany

Re: Long live the ... static variable!

Post by Lupp »

The Static clause is a specialty of "our" Basic (OOo, LibO), and seems to be rarely used.
It restricts the lifetime of the variable to the runtime of a superordinate routine from which it is repeatedly called.
Between two such calls the static vaiable preserves its value.
It's thus "private" to that routine as if it were declared there.

Read chapter
3.7. Scope of variables, subroutines, and functions
specifically subchapter 3.7.1
Of Andrew Pitonyak's famous text "OpenOffice Macros Explained".
You find it on Andrew's page: https://www.pitonyak.org/OOME_3_0.odt
On Windows 10: LibreOffice 25.8.4 and older versions, PortableOpenOffice 4.1.7 and older, StarOffice 5.2
---
Lupp from München
jrgsampaio
Posts: 5
Joined: Fri Aug 07, 2026 9:15 am

Re: Long live the ... static variable!

Post by jrgsampaio »

It is not specific for OOo LibO.
VBasic has it, and also PureBasic, FreeBasic, C, C++, Java, Fortran, etc, etc.

If one reads what I put in the initial post, one will note that its purpose was clearly stated there. Including the static variables lifetime.
Besides, and more important, a static a variable is defined within the procedure and not outside. Therefore, it is NOT visible outside the procedure, and this is very important. a Global variable, as sugested by a guru, does not serve this purpose. (Public and Private are useless for the case.)

A static variable preserves its value between calls ONLY when called from another running procedure. It is NOT preserved between calls from Calc, for example.
Try this count function below, and you will realize that it is not preserved between calls:

Code: Select all

function Fcount() as long
    static icount as long
    icount = icount + 1
    Fcount = icount
end function
Put it in a module under a Standard library of the calling Calc document and call it several times from the spreadsheet.
See if the static variable will keep its value from the previous call. You will disapointely realize that it does NOT retain its value.

Now add the following not so dumb code (put it anywhere - in the same module, in in another module, even in the MyMacros Standard library):

Code: Select all

sub foreverloop()
    do
        wait 10000	' 10 seconds 
        beep		' just to alert that me it's running
    loop
end sub
Put it to run and repeat the test calling the dumb() from Calc... (stop it after finish the test.)
You will be surprized, now, that the static variable retains its value between calls. and NO external procedure can alter its value, as would be the case if a Global variable is used.

The reason is because in calls from Calc, a process is started when Calc calls it and ends after return and the static variable loses its value. But if a procedure is running during the calls (the "forever" loop in the case), the static variable is retained between the calls from Calc, because it should also be available from the running procedure (the "forever") even if it never uses it.

Few of the previous contributers here, if anyone, understood the point. A Global variable would work, but it would be vulnerable to be altered by other procedures; Python is not the answer - using it is not as direct as Basic is; and Static is not rarely used as suggested. How can one tell that? Is there any statistics available supporting this statement? and, if yes, what's ths point? And Pitonyak's macro text does not cover this particular situation. I hope he can one day read this post, consider it, and add the topic in a new version.

As I said in the initial post, I was presenting a solution, and not bringing a question. Somebody may use the solution for specific purposes, as I use myself. Since it is, possibly, the only way that have it working properly, why the critics? If you don't need it don't use it.
LibreOffice 26.2 on Ubuntu 26.04
pitonyak
Volunteer
Posts: 187
Joined: Sun Oct 07, 2007 9:13 pm
Location: Columbus, Ohio, USA

Re: Long live the ... static variable!

Post by pitonyak »

Disclaimer: I did not read the post above, I read a private email and I am assuming that the information is the same.

It has been a long time since I looked at any of this, but the solution of keeping the system running in the background to maintain the value of a variable (or variables) works, but I do not believe that it is documented (so not official) so it is not clear that it is a safe solution; but it clearly works.

I do have a couple of comments.

If I need to save the state of multiple variables, I might create a user defined data type that contains the multiple values in a single variable.

Using a global or static variable is great, but, it does put the responsibility on you to make sure that you are thread safe and that the code is not called more than once. I can think of ways to work around this, but for this specific case, probably not worth the effort to burn brain cells on it until we know it is a problem.

I regularly use a macro inside of a Calc document that uses an iterative method to find a solution (go math). I solved the problem by passing the initial value as a parameter. For my problem, I am finding a specialized IRR (internal rate of return) that differs from the built-in method given all previous transactions. If I add a new transaction, it is expected that the new IRR will be similar to the previous IRR, so that is the starting iteration value. The disadvantage is that I require a row for every "step".

An seemingly obvious solution (that feels dangerous) is to store intermediate values in the Calc document, but you cannot directly modify the sheet that calls the function, so it would need to be on a different sheet or in a different document entirely. That feels like a problem and no idea how fast it would be.
Andrew Pitonyak
http://www.pitonyak.org/oo.php
LO and AOO on Fedora
User avatar
Lupp
Volunteer
Posts: 3761
Joined: Sat May 31, 2014 7:05 pm
Location: München, Germany

Re: Long live the ... static variable!

Post by Lupp »

Spoken aside:
Just a reminiscence: There were also the block concept and the "own" declarations of ALGOL.
I studied that in 1966 and have still the few pages of the "Revised report on ALGOL 60" and the "Manual der ALCOR Gruppe".
Less than 170 pages ISO A5 including the appendices, and next to perfect.
Many famous authors like Backus, Bauer., Naur, ...
It was wondferful ...
You may call it the heroic time of programming. Or a paradise?
On Windows 10: LibreOffice 25.8.4 and older versions, PortableOpenOffice 4.1.7 and older, StarOffice 5.2
---
Lupp from München
jrgsampaio
Posts: 5
Joined: Fri Aug 07, 2026 9:15 am

Re: Long live the ... static variable!

Post by jrgsampaio »

Thanks, Andrew, for your comment, and for spending your time testing the simple codes before issuing your opinion, and realizing that it works (with the running loop but not without it).

In my humble opinion it is not documented... I've searched several sources, including your texts, and The LibreOffice Help https://help.libreoffice.org/latest/en- ... help.html ... when I firstly faced the problem. Right after I confirmed that a Global variable would retain the value, but it is too exposed. The variables could be altered by other processes (unlikely but not impossible). The static variable can only be altered by calls to the function where it is defined.

I concluded that the static variables are retained for call from Calc only if a macro environment is running, which is the purpose of the simple loop presented.
I was concerned about the overhead. The loop as it is - with a "wait <milisecs>" (even a 1 sec wait) - does not noticeably load the CPU (my box is a ASRock X570 Phantom Gamming 4 with CPU Ryzen 9). But if the wait statement is by-passed (comented), the CPU fans rev up wildly, indicating a considerable overhead.

Thanks, I am content with the comment and support.
LibreOffice 26.2 on Ubuntu 26.04
Post Reply