Function Request: Static variables

Another function request; this request is mostly syntax sugar.

We have now local Methods (method defined in a method - which can only be accessed from that method),
local Properties (property defined in a method - which can only be accessed from that method).

I miss the local Fields; a field defined in a method - which can only be accessed from that method.
It is different from a variable in such a way that the local field retains it value between calls to the method. In Visual Basic this is called a Static Variable (see https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/modifiers/static).

A static variable is in essence a private variable in the class that can only be accessed from the method where it is defined.

Example as we can do it now:

type x = class
    private 
        myVar: int := 1;
    public
        method MyMethod();
end;

implementation

method x.MyMethod();
begin
    //in the first call it will print 1, in the second 2, and so on
    Console.WriteLine(myVar);
    MyVar := MyVar + 1;
end;

Example with a static variable:

type x = class
    public
        method MyMethod();
end;

implementation

method x.MyMethod();
begin
    // will initialize the variable to one in the first call, will not change it in the second, third and so on.
    Static MyVar : Int := 1/
    //in the first call it will print 1, in the second 2, and so on
    Console.WriteLine(myVar);
    MyVar := MyVar + 1;
end;

The difference between the first en second example is that in the first example the value of MyVar can be changed in any method, in the second it can only be changed in the method MyMethod.

hmm, so really it’s an instance field of the class, with its access being restricted to the one method?

feels to me that this would be more cleanly expressed as a private field declared close-by to the method itself…

I use them a lot for caching values in VB.Net.
And in essence, local methods and local properties work the same …

I think that a class definition should be as clean as possible, so when a field is only used for one method, it should be defines in that method.

Yes, but not completely.
If the method is a class method, the field is internally a class field, if it is an instance method, the field is internally an instance field.

Just like local methods and local properties, you can do without them and just define them in the class, but for good code readability and local containment you need the local versions.

Further, there is one more difference.
The field MyVar in the first example is initialized when the class is instantiated - regardless if any call to MyMethod will ever be made.
The static in the second example will be initialized on the first call to the method MyMethod.
So it gives some kind of optimization too; it prevents fields from being initialized when they are not needed. (In this example not really much because it is an int, but it can also be a complex class - in that case you really win time and memory).

@mh, @ck
I thought “Maybe I can implement it myself using aspects” …
But I can not set an attribute or aspect on a local variable :frowning_face:, so that did not work …
So I need you guys to implement it for me; unless you can tell me how and where to start.

Yeah, I don’t think you’ll be able to do that via aspects.

I can log a feature request, but it’ll be low priority, as we have a huge lot of things going on right now on the compiler side, already…

1 Like

Thanks, logged as bugs://82729

I just finished my Oxygene only (so no VB code) project.
This was a small one.
I a short time, I will start a huge Oxygene only project, and it should be very nice to have this available for this project.

I’ll bring it p for review again; right now it’s logged as low prio because things are very busy on the compiler side…

1 Like

Carlo tells me it mainly comes down to finding nice syntax. Neither of us likes (ab)using static for this, as this really has a different meaning (even though I realize C abuses kit the same way).

I’ll be thinking about this over the weekend.

Side question : you going to Cafe del Mar on Saturday? We can brainstorm there :tropical_drink:;).

answered in a PM.

I did a quick search.
I found 6 languages that supports this: C, C++, VB, Julia, Rust and Arduino.
And they all call them static variables, using the static keyword.

But maybe persistent as keyword?

var x: int; persistent;

1 Like

yeah, they all just aped C :wink:

maybe. ideally, of we could get away without adding a new keyword that’d be good. I’ll sleep on it.

Just some info behind the scenes on the topic:
https://weblogs.asp.net/psteele/7717

To be clear: in your expectation, would this loc al variable always be shared among the entire class or would it be unique per instance, for instance methods, and unique to the class, for class (“static”) methods?

Imho the second option makes most sense and would be most intuitive, and I assumed that was the goal, but the link you proved mentions the internal var is always static…

essentially:

Foo = public class

  method Bar;
  begin
    var MyBar: String; static;
  end;

  class method Baz;
  begin
    var MyBaz: String; static;
  end;

end;

for each instance of Foo, MyBar would be unique to that instance (but same each time Bar is called), correct?

Yes - C++ supports this, as “local static variable”. It is an interesting feature.

In the C++ standard - I am looking at C++ 20/N4820, which is the most recent draft being worked by ISO/JTC1/SC22/WG21 C++ Standard Committee -

Section 6.6.5.1 “Static storage duration”, it says:

The keyword static can be used to declare a local variable with static storage duration.

So @Theo69’s suggestion of using “static” is the same as what C++ does. I tend to agree with @Theo69, and think it would be somewhat nice to have this.

method x.MyMethod();
begin
    // will initialize the variable to one in the first call, will not change it in the second, third and so on.
    static MyVar : Int := 1;
    //in the first call it will print 1, in the second 2, and so on
    Console.WriteLine(myVar);
    MyVar := MyVar + 1;
end;
1 Like

If the method is an instance method, the local static variable is unique in each instance, and is destroyed as soon as the instance is destroyed.

If it is a class method, the local static variable is unique for the class and will only be destroyed when the program finishes.

Edit:
Both are initialized on the first call only and are thread-safe.

Ok, good. that’s how I understood it. so basically the above becomes:

Foo = public class

  method Bar;
  begin
  end;
  var MyBar: String; private;

  class method Baz;
  begin
  end;
  class var MyBaz: String; private;

end;

on runtime level, plus the extra restriction that the compiler won’t make the field available outside the single method.

Somewhat more complicated:

type
  foo = public class
  private
    var fbarLock: Object := new Object();
    var fMyBar: String;
    property MyBar: String read getMyBar write setMyBar;
    method getMyBar: String;
    begin
      locking fbarLock do
        exit fMyBar;
    end;
    method setMyBar(value: String);
    begin
      locking fbarLock do
        fMyBar := value;
    end;

    class var fbazLock: Object := new Object();
    class var fMyBaz: String;
    class property MyBaz: String read getMyBaz write setMyBaz;
    class method getMyBaz: String;
    begin
      locking fbazLock do
        exit fMyBaz;
    end;
    class method setMyBaz(value: String);
    begin
      locking fbazLock do
        fMyBaz := value;
    end;

  public
    method Bar;
    begin
    end;

    class method Baz;
    begin
    end;
end;

Hmm, access gets automatically locked? how about we require “locked;” on the var to enable that:

method Bar;
  begin
    var MyBar: String; static;
    var MyBaz: String; static; locked;
  end;

(with static still being a placeholder for the proper syntax)