Wish Static / Persistent local variables

copanut

Member
Licensed User
Would love to have the ability to define local variables that have persistent value, like private globals, but have scope only in the sub where they are declared. The declaration could still be "Private", with the scope implicit from the location of the declaration, or it could be something distinctive like "Static" or "Persistent".

For example:

Current Method:
Sub Process_Globals
    Private globalvar as string = ""
    Private var1 As Int
    Private var2 As Int
    Private var3 As Int
End Sub

Sub examplesub1
    var1 = var1 + 1
    globalvar = "example1 count: " & var1
End Sub

Sub examplesub2
    var2 = var2 + 1
    globalvar = "example2 count: " & var2
End Sub

Sub examplesub3
    var3 = var3 + 1
    globalvar = "example3 count: " & var3
End Sub

Proposed Method:
Sub Process_Globals
    Private globalvar as string = ""
End Sub

Sub examplesub1
    Static myvar As Int
    myvar = myvar + 1
    globalvar = "example1 count: " & myvar
End Sub

Sub examplesub2
    Static myvar As Int
    myvar = myvar + 1
    globalvar = "example2 count: " & myvar
End Sub

Sub examplesub3
    Static myvar As Int
    myvar = myvar + 1
    globalvar = "example3 count: " & myvar
End Sub

This is, of course, a nonsense example, but it should serve to illustrate the concept. In the proposed approach, myvar is, in all respects, the same as three global private variables except it is declared within the sub where it is used (and ideally would have visibility/scope only within that sub).

A compilation implementation could be as follows: when the Static keyword is encountered, generate a Java name that combines the sub with the static variable, e.g. examplesub1_myvar, so for Java purposes it could be treated as any private global, while having the benefits of scope and modularity within B4X.

Using private globals within B4X as in the "Current Method" example certainly works, but for large modules with lots of subs it can become unwieldy, messy, and harder to maintain. One may do a lot of scrolling between the Globals section and subs that are scattered around, because the variable declarations may be very distant from the sub where they are used. The proposed approach is more modular and maintainable. It's also easier to make cohesive subs that can be more easily copied and pasted from module to module, or from project to project. Also, this approach allows the Globals section to be focused on only those variables that actually are used in multiple subs within the module, or are publicly accessible.
 
Last edited:

Cableguy

Expert
Licensed User
Longtime User
You can use constants...
Dim const myvar as int = 50

A quick search in the forum will give you more details
 

stevel05

Expert
Licensed User
Longtime User
It seems to me that you are creating pseudo structures with the same content (in the example at least). This type of structure would probably be best served with a class, where you only have to write the code once.
 

copanut

Member
Licensed User
You can use constants...
Dim const myvar as int = 50

A quick search in the forum will give you more details

But a constant is "constant", not a variable. The value of a variable can be changed, but the value of a constant cannot, so they don't serve the same purpose.

I have searched the forum on the issue of static/persistent local variables and have seen the question has been raised before over the years, and I have seen the suggestion of using a constant, but unless I'm missing something fundamental, a constant is not a solution for the proposed issue.

Note:

1667858365886.png
 

copanut

Member
Licensed User
It seems to me that you are creating pseudo structures with the same content (in the example at least). This type of structure would probably be best served with a class, where you only have to write the code once.

Yes, you are quite right, but this is why I called it a nonsense example. It is for illustration purposes only. Imagine that each sub has completely different functionality, rather than the simplistic identical functionality that I have shown. For example:

Updated Illustration of Proposed Approach:
Sub Process_Globals
    Private globalvar as string = ""
End Sub

Sub CalculateFourier
    Static myvar As Int
    ' Do some calculations for fourier transform and track how many times this is done.
    myvar = myvar + 1
    globalvar = "example1 count: " & myvar & " " & transformResult
End Sub

Sub CollectGeoCode
    Static myvar As Int
    ' Do some geocode computations and track how many times this is done.
    myvar = myvar + 1
    globalvar = "example2 count: " & myvar & " " & latitude
End Sub

Sub UpdateDatabase
    Static myvar As Int
    ' Do some database logic and updates and track how many times this is done.
    myvar = myvar + 1
    globalvar = "example3 count: " & myvar & " Updated: " & datetime.now
End Sub

Further, the same idea would apply within a class, where there are class globals, but persistent variables local to subs will provide greater clarity, maintainability, and reusability in many cases.

The point is that locally scoped, persistent variable data is a normal component of software engineering. It would seem fairly easy to implement in B4X because the exact mechanism of private globals can be used, unchanged, and scoping is provided simply by the B4X compilation/preprocessor transforming the variable into a unique name with global scope. The local static variable does not have a unique name, but with the subs name prepended it becomes unique, so even though Java sees it as a global private, within B4X it is locally scoped and physically lives within the sub.

The IDE sees it this way:
Code as entered in IDE:
Sub Process_Globals
End Sub

Sub examplesub1
    Static myvar As Int
End Sub

The compiler transforms it to the Java equivalent of this:

How the compiler treats it:
Sub Process_Globals
    Private examplesub1_myvar as int
End Sub

Sub examplesub1
    examplesub1_myvar = examplesub1_myvar + 1
End Sub

Thus we gain all the software engineering and modularity advantages of persistent locally scoped variables with what would seem to be very minor modification to the B4X compiler/preprocessor.

The programmer is able to embed the relevant persistent variable declarations within the sub where it is used rather than locating those declarations in a distant part of the module, potentially thousands of lines of code away, in a mass globals section that contains variables used uniquely in many different scattered subs in the module.

Another point here is that Java does not have the concept of static local variables (unlike the vast majority of programming languages like C, C++, Ada, Visual Basic, etc). With a simple tweak, B4X can provide what Java lacks, once again showing the superiority of B4X as a programming platform.

In Visual Basic it looks like this:
Static local variable in VB:
Function updateSales(ByVal thisSale As Decimal) As Decimal
    Static totalSales As Decimal = 0
    totalSales += thisSale
    Return totalSales
End Function

And yes, I know B4X is not Visual Basic. It's also not Java. I think it aspires to be better than both!

Other examples below. Most languages support something similar.

Static local variable in C++:
void incrementAndPrint()
{
    static int s_value{ 1 }; // static duration via static keyword.  This initializer is only executed once.
    ++s_value;
    std::cout << s_value << '\n';
}

Static local variable in Perl:
sub count {
    state $counter = 0;
    $counter++;
    return $counter;
}
 
Last edited:

stevel05

Expert
Licensed User
Longtime User
Even so, by capturing and accessing data about the calculation, to my mind it becomes a process. I still think the simplest and most legible structure would be to use classes.

I only comment on wishes like these because I like to understand what the wishes of other users are and why they are asking for them.
 

copanut

Member
Licensed User
Even so, by capturing and accessing data about the calculation, to my mind it becomes a process. I still think the simplest and most legible structure would be to use classes.

I only comment on wishes like these because I like to understand what the wishes of other users are and why they are asking for them.
And your comments are appreciated. But, my feeling is you are focusing too much about the meaningless content of the illustration rather than the concept of encapsulating persistent data items within their relevant subs rather than globally and disconnected from the relevant subs. This concept is equally pertinent within a class module as it is within a static module. Structuring common code within a class that can be instantiated is great as well, but is different from the idea I am trying (and perhaps failing) to express.

Perhaps put a different way, a class is a logical concept with a physical structure. I'm talking about the physical aspect: are data items located in a way that is friendly to modularity and its benefits? That question and its answer applies to both types of module: class and static.

I'm probably doing a bad job of expressing this, and if so I apologize.
 
Last edited:

LucaMs

Expert
Licensed User
Longtime User
Local static variables are often useful (mainly to avoid using module-level global variables).

Anyway, this has already been asked (whishlist forum) many years ago and perhaps several times. Since it has not been implemented, there will be compelling reasons and it is useless to ask for it again.
 

copanut

Member
Licensed User
Local static variables are often useful (mainly to avoid using module-level global variables).

Anyway, this has already been asked (whishlist forum) many years ago and perhaps several times. Since it has not been implemented, there will be compelling reasons and it is useless to ask for it again.
Or, maybe there were just too many other higher priority things in the fire, or maybe the intent was not well explained. In any case, while I have seen the issue raised years ago, I do not recall seeing any sort of official response much less hint of a compelling reason against. I think I have shown that the request could be implemented without any structural redesign as "under the covers" in Java, the variables would be global privates exactly as they are now. Perhaps there is some philosophical reason for not doing it, but I see no technical or substantive resource reason, so I will exercise my right as a licensed member to beat my head against the wall by asking again.

In fact, I see two instances of the request coming up in this forum previously. The first is by you in 2017:


There was no response in that thread by anybody.

The second one was by Marc S in 2019:


This thread had some responses. Cableguy suggested using constants, as he also suggested for me above (and I thank him for the idea), but as I responded above to him, so Mark S also pointed out in the 2019 thread that a constant is not a variable. It cannot act as a state variable because its value cannot be changed. Others suggested using globals, which makes sense since that thread was not specifically about static variables local to a sub, but of course that does not address the issue of a local static raised by you and me. Finally there was a response by Erel that the request was not clearly defined, and that was the end of the discussion.

I see that you also raised the same thing, obliquely, in this 2020 thread which was on a different topic.:


Once again, there was no answer, official or otherwise, on the subject.

I did not find any other instances of this request using the forum search "static local".


So I am clearly defining the request: make a change to the compiler/preprocessor that detects a static variable declaration in a sub, modify the name of that variable to prepend the sub name so that the variable is unique on a module level, and elevate that variable to treat it exactly as a global private variable. No other changes are required to implement this. Reason? Exactly what you stated in 2017 and again here, that this would allow programmers to avoid global module variables except in cases where doing so makes sense, i.e., when they need to be accessed by multiple subs in the module.

If there is a good reason (or even a not good reason) for declining to do it, it would be helpful to have that stated in a response so that some fool like me doesn't come along five years from now, fails to find an answer via search, and then posts the request again.
 
Last edited:

LucaMs

Expert
Licensed User
Longtime User

copanut

Member
Licensed User
Well this is like asking a question before searching the site, it would be better not to.
Not at all. Of course I searched first, as should be clear. I did not find any discussion on the subject at all, and only one direct mention. The closest was your post five years ago, but it was brief, lacked examples, and there was no ensuing discussion. It's not clear to me that it was ever on the radar for consideration. Priorities can shift over time, and items that may not have been considered before might be considered now or later if they get a "bump" from a user request. I see nothing wrong with registering my "wish", explaining it in some detail, and with some thought about the implementation considerations, so that if it wasn't on the radar from the prior brief mention, it might be now.

Someone coming along in five years, assuming the feature still does not exist by then, will search and find this more fullsome discussion, and so perhaps will more reasonably conclude that the feature will never happen if it hasn't already by then, because now, at least, it has been properly discussed where it was not before.

As it happens, I care about this product and believe in it. I acquired it to make a specific app that is now complete and distributed worldwide on Android, iOS, and Windows. At the moment I don't plan to create more apps as I am retired and have other things to do, so the feature suggestion is not a selfish one. I think it makes the product better without adding complexity, and it would be helpful to future app developers. This is to the benefit of B4X/Anywhere Software and so to me is worth posting for that reason alone.

Erel is perfectly free to not respond, and I am perfectly free to ask, so it would seem there is no problem. What I have been interested in is having a full airing of the issue, which has not been done prior to this.

My only objection is to this statement: "Since it has not been implemented, there will be compelling reasons and it is useless to ask for it again". I object for these reasons: I don't see the lack of the feature, in and of itslef, as evidence that it won't be added; I see no evidence that there are compelling reasons to not do it at some point and I don't think prior discussion exists to support that conclusion; and I don't think it's useless to ask, as requests are a metric of interest. As I say, at least now there has been a decent discussion with examples, so the effort is not useless as at least future users will have a better point of reference.

All that said, I do enjoy the forums and have read and appreciate your many contributions to it.
 

LucaMs

Expert
Licensed User
Longtime User
Not at all. Of course I searched first, as should be clear. I did not find any discussion on the subject at all, and only one direct mention. The closest was your post five years ago, but it was brief, lacked examples, and there was no ensuing discussion.
Which means you later found it.
However, writing a question or, in this case, a "wish" even if you have not previously found something similar, is certainly not a crime.
I don't remember mine from those times and I haven't even read it now; I suppose I just asked them to implement static local variables, knowing that Erel knows them even better than myself.

Erel is perfectly free to not respond
The only very serious mistake of Erel, for which he should undergo a criminal trial, was not having put a Like on my previous post 😂
 

copanut

Member
Licensed User
Which means you later found it.
LOL, language is a funny thing. I might think I am being clear and careful with my words, but reality proves otherwise. When I said I found no discussion, I meant that literally. I searched for the topic long before posting the wish, and the first thing I found was your 2017 post. That post contained no discussion of the subject: no elaboration of intent, no dialog from others, no follow up from anybody. That's what I meant by "I found no discussion". I did not mean that I found a discussion later, because I did not. Further, that post, and its over five years old, so perhaps raising again for consideration and doing so with more specificity. Seeing no other direct mention of the idea, I pondered for a bit and decided to post my wish with some detail. Call me crazy.

By now, actual discussion has been exceeded by meta-discussion. The big irony is that you and I are 100% in agreement on the technical idea! 😁

(BTW, I may spend a little time creating my own pre-processor to implement static locals so that I can enjoy the benefits of the concept without it being built into the IDE, but adding it directly into the IDE would be so much better.)
 
Last edited:

William Lancee

Well-Known Member
Licensed User
Longtime User
I haven't missed this feature, but that might be because I don't work with groups of coders.
Generally, I don't have a problem with keeping track of globals in my Namespace.

As I understand, the idea is:
1. Have a set of persistent variables in a sub whose values are restored on entry to the sub.
2. These variables should have local scope and not be directly available by name ouside the sub.

The code below will do that. It uses a small class, but only for two methods and for the keeping the datastore more private.
I thought that there would be too much overhead, but as you can see, this doesn't seem to be a problem.

However, I agree with the OP that having a native Static type would be much more elegant.

B4X:
Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    Private SX As Persistent    'A small standard class for handling static/persistent variables
End Sub

Public Sub Initialize
    SX.Initialize
End Sub

Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
End Sub

Private Sub Button1_Click        'Each click will perform a 1000000 calls to IncrBy1 Total time = 55 milliseconds
    Dim marker As Long = DateTime.Now
    For i = 1 To 1000000
        IncrBy1
    Next
    ReportResults(marker)
End Sub

Private Sub IncrBy1
    Dim Statics As Map = SX.RetrieveStatics("IncrBy1")                'restores sub-specific mapped values
    Dim n As Int = Statics.GetDefault("n", 0)                        'The GetDefault feature is useful here
    Dim factorial As Float = Statics.GetDefault("factorial", 1)        'Automatic conversion from Object
    
    n = n + 1
    factorial = factorial * n
    
    SX.SaveStatics("IncrBy1", CreateMap("n": n, "factorial": factorial))
End Sub

Private Sub ReportResults(marker As Long)
    'The values of the static variables in "IncrBy1" are accessible outside the sub, but not by direct reference
    Dim Statics As Map = SX.RetrieveStatics("IncrBy1")
    Dim n As Int = Statics.GetDefault("n", 0)                'This n is not the same as the n in "IncrBy1"
    Dim factorial As Float = Statics.GetDefault("factorial", 1)
    
    Log(n & TAB & factorial)    '1000000    Infinity
    Log(DateTime.Now - marker)    'On my system in release mode this duration settles on approx 55 milliseconds for a million calls
    Log(TAB)
    
    SX.SaveStatics("IncrBy1", CreateMap("n": 0, "factorial": 1))    'reset starting values
End Sub

'The Persistent Class

B4X:
Sub Class_Globals
    Private fx As JFX
    Private StaticVars As Map
End Sub

Public Sub Initialize
    StaticVars.Initialize
End Sub

Public Sub RetrieveStatics(SubName As String) As Map
    If StaticVars.ContainsKey(SubName) = False Then
        Dim Statics As Map
        Statics.Initialize
        StaticVars.Put(SubName, Statics)
    Else
        Dim Statics As Map = StaticVars.Get(SubName)
    End If
    Return Statics
End Sub

Public Sub SaveStatics(SubName As String, restore As Map)
    StaticVars.Put(SubName, restore)
End Sub
 

copanut

Member
Licensed User
It's an interesting thought, thank you. I do something very similar to this for managing large amounts of data collected from REST databases, but hadn't thought to use the approach to mimic local statics. I agree that it isn't as elegant or efficient as the proposed approach, but it's a useful workaround for consideration.
 

LucaMs

Expert
Licensed User
Longtime User
the first thing I found was your 2017 post. That post contained no discussion of the subject: no elaboration of intent, no
It wasn't necessary. Erel is perfectly familiar with static local variables, I certainly didn't have to explain anything or argue more.
Once created that "wish", he made his own decisions, as he specified in that more general and fundamental post.

Continuing to write in this thread is a waste of time.
 

copanut

Member
Licensed User
It wasn't necessary. Erel is perfectly familiar with static local variables, I certainly didn't have to explain anything or argue more.
Once created that "wish", he made his own decisions, as he specified in that more general and fundamental post.

Continuing to write in this thread is a waste of time.
Unlike you, I lack the ability to read the man's mind. And do I need to point out that threads like this are not just for Erel, but for users who are searching for discussions on a topic, including alternatives and workarounds, some of which have been helpfully submitted by others on this thread that were not in any previous thread.

But you are free to stop wasting your time further. Thanks for your input.
 
Last edited:

netsistemas

Active Member
Licensed User
Longtime User
With what we have, I would create a kind of LIST or ARRAY of PUBBLIC variables. Then, in the subs, instead of using variables, you would use calls to that list or a function that returns the value of a variable name. In this way, the operation can be better encapsulated. I think it goes without saying that the name of the variables must be unique, so I would add the name of the module that requests the value.
 
Top