Got two questions about Keyboard Maestro variables:
On the Wiki it says variables can be Global, Instance and Local.
I am struggling to understand: When would an Instance or Local variable be useful over a global variable? I’ve read the wiki several times but I can’t wrap my head around the usefulness of Instance/Local variables over just using global variables all the time. Do global variables have a disadvantage that Instance/Local variables solve? It would be nice if there was a pro/cons list for each type to better understand them.
In the Variable Dot Notation section it says that the calculation field allows you to use dot notation.
Example “Variable.x” to get the X coordinate of a variable. Or "Variable.width" to get the width of a rectangle or size.
I don’t understand where would these values come from. For example, if I created a variable called “Shape” and set it to a value of 10, where would the width value come from?
Would I have to specifically set a value of Shape.width = 10 earlier in the macro? I’m sure I would. But it says that Dot Notation is used in the calculation field. So does that mean earlier in the macro, I’d have to create a calculation field that says Shape.width = 10. And then put a separate calculation field later on to access the “Shape.width” value? Is that right? Or can I set "Shape.width" outside of a calculation field?
Sorry if these questions seem a little basic. I am trying to better learn variables to make better usage of them. I did search around but am still stuck on these two areas. Thanks in advance for help!
Global Variables are saved onto your computer, with the data saved as well. So, they remain after the Macro has run. That can be good.
Example: You use a Variable to save a folder location and each time you run the Macro you want to go to that same folder location. By just using the Global Variable you have defined you will have access to that folder location in any Macro that needs it. When you update the Variable to a new folder location all the Macros that use that Global Variable will have the new folder location.
But the downside of only using Global Variable is that they add clutter (unless you deliberately delete them). Quite quickly you will end up with lots of Variables that you can't remember why you created. If you only need the Variable to be around for a single run of the Macro that's where Local and Instance Variables are good.
Local Variables When the Macro they are used in has finished its run their data vanishes. Often you need to make use of Variable in a Macro to calculate stuff or to receive input from a User. But if these values are going to be generated each time the Macro is run there is no need to have them saved.
Instance Variables are similar to Local Variables. The same idea is that they don't get saved. The difference it that they get shared between Macros if more than on Macro is used in a routine. At the end of the routine they will disappear. (If you have a Macro that has an Execute Macro Action in it the Variable will be shared with that other Macro).
The positions of the values in the Variable are assumed based on what Keyboard Maestro expects to find in the Variable.
Example: if you have 122,13,45,22 saved in a Variable called MyVariable that is four digits separated by commas. If they represent the coordinates of a Window then Keyboard Maestro would expect the third value to be the the width so, MyVariable.width could be used to get 45 into a calculation.
The notation MyVariable will achieve the same thing and is simpler to use I think.
I'd add another, important, downside. Because they are "shared" they be changed by more than one macro -- Macro A sets Global_myVar, Macro B changes Global_myVar, Macro A reads in a different value from Global_myVar than the one it set.
As @Zabobon said, that's what you want when passing data between macros. But it is bad when you don't want that to happen, and all to easy to do accidentally either by duplicating macros to edit, copy/pasting actions between macros, or simply because we're creatures of habit and often use the same names to refer to similar "things".
It's a general rule of programming that you should "scope" your variables as tightly as possible to prevent these problems. So choose Local if you can, Instance if using sub-macros, and Global if you want data to persist, be shared between macros, or be easily edited in the Variables tab of KM Preferences (which can be useful when troubleshooting).
Thanks! So if I was making a macro to work in graphic design software, and as part of the Macro I wanted enter height/width values, I should just create two separate variables E.g. VarShapeWidth = 10, VarShapeHeight = 20? Because if I did VarShape.w = 10 and VarShape.h = 20, it would confuse Keyboard Maestro as it has it's own thing it expects for .w and .h. Is that correct?
As mentioned, global variables are great if you want values to persist from one execution of a macro to another. If your macro has multiple values that need to persist, to avoid global variable clutter, I suggest grouping the values and adding them as separate keys in a single macro dictionary. Dictionaries are effectively global, although unlike global variables, they are not available for browsing in the Keyboard Maestro Preferences. Alternatively, the contents can be viewed by building a simple macro using the KM dictionary actions or by using other macros available on this forum. My personal favorite is @DanThomas' Variable Inspector Prompt and Dictionary Editor.
Dictionaries can seem intimidating initially, let alone applying them as I've suggested above. But with a little practice, you will find them to be very useful for this application and many others. For a simple example, you can check out a macro I've shared elsewhere: Dialog with Dynamic Popup List
Yes. The Dot Notation is only useful in a very few limited scenarios.
Generally, like you say, you would have each value in a separate variable.
Have values separated by commas in the Variable and access them with the notation MyVariable etc as I mentioned. Or use Dictionaries as @Nige_S has mentioned. But keeping things simple yes, use a separate Variable for each value would be best in 99% situations I think.
That would actually not work at all. That's why the Dot Notation is extremely limited. You can't decide yourself what to put after the Dot - you can only use the small number of Keyboard Maestro pre-defined words like .left .top .width
My advice is to forget about Dot notation
What you are trying to do with the above example is basically how Keyboard Maestro Dictionaries do work.
Instead of VarShape.w = 10 you would be setting a Dictionary Value something like:
Dictionary = VarShape (or whatever you want to call the Dictionary)
Key = w (or whatever you want to call the key)
Value = 10
But in most situations I would use a separate Variable for each value and name the Variables carefully so I know what is going on.
Yes. As @Zabobon says, the general case for arrays is reference by index -- myArray is a special case and return the number of items in the array, myArray the first item, etc.
Dot notation is a special case restricted to coordinate (x, y) and rectangle (top, left, width, height) arrays and is only available in calculations. So you could use a "Set Variable" action to set myRect to 0,0,20,20 and then in another action %Calculate%myRect.height + 100%.
One advantage of this is readability -- it'll be a lot easier in a year's time to grok that you're increasing the height of your rectangle by 100 with dot notation than with indexing. It's also a quick way to get other rectangle values -- you can get the right edge of a window with myWindow.right rather than calculating it with myWindow + myWindows.
Thanks for your explanation. One last question, in my previous post, I made a mistake. I should have typed "VarShape.width = 10" and "VarShape.height = 10".
If I used dot notation like that, would it be okay? Or am I better forget about it (as KM doesn't work like that)?
The reason I ask, is because a lot of my variables are for graphic design apps. So being able to use values like .width, .height etc, would cut down on the number of variables I create and it would make everything more readable when looking back after a year.
Bear in mind that the dot extension is for accessing numbers that are already in the Variable. If your Variable VarShape contains 21,33,44,88 for example you can use the dot notation to retrieve one of those numbers, or to perform a calculation using those numbers (like to work out the mid point where the window is positioned on screen). In other words you would not create a variable VarShape.width = 10. But you would use the syntax VarShape.width to retrieve one of the four numbers already in VarShape. And you could only use that dot notation in a Calculate field (not in a text field).
By coincidence there is another Thread on this exact thing which explains it much better than I can. The answer from @peternlewis in this post is very good I think:
Thanks for all the help! Lately, I have been using instance and local variables.
(e.g. "instance__list", "local__list").
But I notice when I create a new macro and click on the "insert token" option, all the local and instance variables I have created in all macros appear in that list, even though this is a new macro that doesn't have any local/instance variables in it.
Is that correct? I was under the impression that local/instance variables only exist in the macro they were created in and so I was not expecting to see them in the "insert token" option of a newly created macro.