My experience is that indeed "static" can not be used at function scope. There is directly a translation-error.
If I declare a variable at class scope without "static" , the variable can be used in different member functions of the class, but it does not "hold" its value. For example, when I set the value of a variable in a function "initialize()" of a "WatchUi.BehaviorDelegate" class, this value is not taken over in the function onUpdate(dc) in the same instance of the class. Although the variable can be used in onUpdate(dc), it does not have the value it was given in initialize() (in my case, it had the value given to it in an old instance of the class, which was already popped). The use of "me" or "self" does also not help.
Very frustrating.
Firstly I solved the problem in making the variable global, but that is unsatisfactory. Now I solved it in that I declare the variable as "static" at class scope. This also works and at least the variable is only used in the class (probably with program-lifetime, independent in which instance of the class).
Still not satisfying because I would like a possibility of a variable having the lifetime as long as the instance of the class exists, but only for that instance. With the "static" keyword the variable has lifetime though in every instance of the class.
At least it seems that declaring a variable at class scope without the static keyword is not the same as with it.
My experience is that indeed "static" can not be used at function scope. There is directly a translation-error.
That may be the case now, but I don't believe that was the case then.
If I declare a variable at class scope without "static" , the variable can be used in different member functions of the class, but it does not "hold" its value.
If you want a variable that maintains its state separately for each instance of a class, you need to make it a non-static variable of that class.
class MyView extends WatchUi.View { hidden var updateCounter = 0; function initialize() { View.initialize(); // you coould also have initilaized updateCounter here... } function onUpdate(dc) { System.println(updateCounter); ++updateCounter; } }
This will allow multiple objects to have their own values, and the state within a given object will be maintained.
If you want a variable that maintains its value for all instances of a class, you can make it a static class variable or a module variable (global is a module) like you've described above:
class MyView extends WatchUi.View { hidden static var updateCounter = 0; function initialize() { View.initialize(); } function onUpdate(dc) { System.println(updateCounter); ++updateCounter; } }
The value of updateCounter is shared across multiple instances of the MyView class.
MonkeyC is very java-like in many respects. Java doesn't have support for static local variables either, so it isn't really a great surprise that MonkeyC does not.
First of all, I erroneously logged in under 8941163 which I never use actually, I prefer my account longtrousers.
Anyway, thanks for your time Travis.
I indeed did experience the behaviors of "static" as you describe.
However, a non static variable of a class behaved differently than how you describe it. I must say I did not call it "hidden var" but just "var", but that should not influence the lifetime, does it?
I initialized it at declaration at class level, and did also an assignment in function initialize().
I assigned it differently somewhere in function onUpdate(dc).
This all worked in the first instance of the class. After popping this instance and pushing a new instance of the class, the variable did not have the value as assigned in initialize(), but it had the value which it got in onUpdate(dc) of the (popped) former instance. To my point of view, in the new instance the variable should, at the beginning of onUpdate(dc), have the value assigned in initialize(). This would be the correct behaviour as you describe it.
I quote the program part here under (the variable under consideration is "doOnlyOnce"):
using Toybox.WatchUi; using Toybox.System; using Toybox.Lang; using Toybox.Activity; using Toybox.ActivityRecording; using Toybox.Timer; using Toybox.FitContributor; class arjensappDataScreen extends WatchUi.View{ static var doOnlyOnce = true; // var doOnlyOnce = true; does not work static var y1Text = new[11]; static var x1Text = new[11]; static var fontValue1; static var fontValue2; static var y2Text = new[11]; static var x2Text = new[11]; static var dimText1 = new[2]; static var dimText2 = new[2]; static var textJustify= new [11]; static var doOnShow; static var doEveryFiveSeconds=0; static var doEveryTenSeconds=0; function initialize() { WatchUi.View.initialize(); me.doOnlyOnce = true; System.println("INITIALIZE" ); System.println("me.doOnlyOnce: " + me.doOnlyOnce); } function onLayout(dc) { } var myTimer = new Timer.Timer(); function timerCallback() { WatchUi.requestUpdate(); } function onShow() { myTimer.start(method(:timerCallback), 1000, true); doOnShow = true; // me.doOnShow = true; } function onHide() { myTimer.stop(); } function onUpdate(dc) { var currentActivity = activity[config][currentLeg]; var numberOfFields = field [currentActivity][0]; currentGlobalActivity= currentActivity; if (doEveryFiveSeconds == 5) { doEveryFiveSeconds = 1; } else { doEveryFiveSeconds++;} if (doEveryTenSeconds == 10) { doEveryTenSeconds = 1; } else { doEveryTenSeconds++;} // doOnlyOnce is true at this point in the first instance of arjensappDataScreen, // but false in the second instance when not declared as static if (me.doOnlyOnce) { me.doOnlyOnce = false;
Hello again.
I made a small testprogram which confirmed the behavior you indicated.
This is the small testprogram:
/ // Copyright 2015-2016 by Garmin Ltd. or its subsidiaries. // Subject to Garmin SDK License Agreement and Wearables // Application Developer Agreement. // using Toybox.WatchUi; using Toybox.Graphics; using Toybox.System; using Toybox.Application; class MyApp extends Application.AppBase { function initialize() { AppBase.initialize(); } // onStart() is called on application start up function onStart(state) { } // onStop() is called when your application is exiting function onStop(state) { } // Return the initial view of your application here function getInitialView() { return [new testView(), new testDelegate()]; } } class testView extends WatchUi.View { function initialize() { View.initialize(); } function onUpdate(dc) { System.println("onUpdate in testView"); var dy = dc.getFontHeight(Graphics.FONT_SMALL); var x = dc.getWidth() / 2; var y = dc.getHeight() / 2; dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK); dc.clear(); dc.drawText(x, y, Graphics.FONT_SMALL, "testView", Graphics.TEXT_JUSTIFY_CENTER); } } class testDelegate extends WatchUi.BehaviorDelegate { function initialize() { BehaviorDelegate.initialize(); } function onMenu() { return false; } function onSelect() { var viewX = new MyView(); var delegateX = new MyViewDelegate(); WatchUi.pushView(viewX, delegateX, WatchUi.SLIDE_IMMEDIATE); return false; } function onBack() { return false; } } class MyView extends WatchUi.View { var a = 0; static var b = 0; var c = 0; static var d = 0; function initialize() { View.initialize(); // you coould also have initilaized updateCounter here... a = 0; b = 0; } function onUpdate(dc) { var dy = dc.getFontHeight(Graphics.FONT_SMALL); var x = dc.getWidth() / 2; var y = dc.getHeight() / 2; dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK); dc.clear(); dc.drawText(x, y, Graphics.FONT_SMALL, "MyView", Graphics.TEXT_JUSTIFY_CENTER); System.println("a: " + a); System.println("b: " + b); System.println("c: " + c); System.println("d: " + d); a= 1; b= 1; c++; d++; } } class MyViewDelegate extends WatchUi.BehaviorDelegate { function initialize() { BehaviorDelegate.initialize(); } function onMenu() { return false; } function onSelect() { return false; } function onBack() { System.println("hier"); WatchUi.popView(WatchUi.SLIDE_IMMEDIATE); return true; } }
and this is the console output (it appears, that "onUpdate" is always called twice after creation), whereby "MyView" was created in plural instances:
onUpdate in testView onUpdate in testView a: 0 b: 0 c: 0 d: 0 a: 1 b: 1 c: 1 d: 1 hier onUpdate in testView onUpdate in testView a: 0 b: 0 c: 0 d: 2 a: 1 b: 1 c: 1 d: 3 hier onUpdate in testView onUpdate in testView a: 0 b: 0 c: 0 d: 4 a: 1 b: 1 c: 1 d: 5 hier onUpdate in testView onUpdate in testView
There must thus be something rotten in my other program which has the unexpected behaviour.
I think I have the same problem as in this topic:
and have to solve this.
Yes this was the problem: the onUpdate() of a former already popped view was still wandering around.
I solved it in that I made a global variable which is incremented every time an instance of the view is created and gave a local variable in class scope the value of the global variable (in initialize()). So every instance becomes its own number.
onUpdate() knows now which instance it is in: if local variable == global variable it is executed, otherwise not because it is doing the old (already popped) instance.