Local vs Instance variables

I know this has been asked a few times, but here's one more time, since I've never used Instance variables in the past:

1 - According to Peter's answer to the post I'm sharing below, a Local variable is only available in the macro that called it, whereas an Instance variable can be sent to a "sub macro" when we use "Execute a Macro" action. So I can send Instance__myVar from Main Macro to the macro Sub Macro that I execute using the "Execute a Macro" action, but not Local__myVar. Right?

2 - This question was never answered:

so I ask it again: what's the real advantage of using Local variables when Instance seems to do the same thing, and more?

Local Variables work for a single Macro and have their values emptied at the end of each Macro run (like the way AppleScript variables work).

Instance Variables are for when you have a chain of Macros running and want to use a Variable's value for the whole chain of Macros - but still empty the Value at the end of the whole run.

Global Values persist between Macro runs.

So, it all depends what you want to do and how long you want the variables to persist.

And you could also say, Global Variables do the same thing and more.

It's all to do with when the Variables have their values emptied. In the past all Variables in Keyboard Maestro were Global. Then a request was made for Variables that did not persist between runs, which led to Local and Instance Variables being available as options.

Now that Keyboard Maestro has Subroutines which can in effect use Local Variables, Instance Variables aren't as needed as they were perhaps in the past - at least that is what I have found.

1 Like

Yes, but Global variables are not deleted unless we specifically say so, unlike Local and Instance, so I see Global variables as one thing, and then Local and Instance being part of the same "group" with that advantage of Instance variables being able to be used across multiple macros.

So again, if Instance variables are more flexible than Local variables, why use Local at all? They are both delete at the end of the macro (or group of macros), but Instance can be used any time, anywhere, so why use Local?

I never used Instance, because I never really took the time to understand them, but now that I see what they can do and looking at some of my macros, I can see how I can actually use them more than Local to create more flexible workflow (using sub macros).

Why do you think Instance are not as needed compared to Local?

Most of my Macros are self contained and don't call other Macros as part of their run.

When I do call other Macros it is now mostly in form of Subroutines and they can use the Local Variable's values without having to use Instance Variables.

I'd only use an Instance Variable if I wanted to chain Macros together and for some reason didn't want to make the chained Macro an actual Subroutine.

The reason there are options is that historically there have been:

  1. Global Variables
  2. Local and Instance Variables
  3. Subroutines

The good thing is that with each addition the old behaviour was still retained, giving you a choice of how to work and ensuring that old Macros that were written before the new features still work.

2 Likes

Ok I understand what you mean.
Some of the "old" approaches are there for "legacy" / compatibility purposes, I guess?

So basically when you want to use variables in sub-macros, using "Execute Subroutine" does the same as using "Execute a Macro" without the need to set Instance variables, right?

Do you still use "Execute a Macro" at all, even if you just want to trigger a certain macro? Or do you just use "Execute Subroutine" to avoid having different types of actions?

1 Like

I use "Execute a Macro" all the time, when it doesn't need to return a value, and either doesn't need a parameter, or only needs one parameter. Although lately I've been using subroutines more often, even when only needing one parameter, in case I need to add another parameter later.

1 Like

Thanks for the feedback!

One of the "advantages" of using "Execute a Macro" is that you don't need to add a trigger to the sub-macro. Not that it feels like a burden, but it's just something you don't have to think about as opposed to "Execute a Subroutine".

But I'm glad I took the time to finally learn about all these things today (Instance variables, subroutines, Execute a Macro with parameter). I can see how some of my macros will benefit from these, especially subroutines :slight_smile:

Here's an example I use all the time: Many of my macros have loops with counters, and I use local_theCounter for those loops as a matter of course. If I have a macro that calls other macros, and I were to use instance_theCounter, then there's a chance (depending on the loop and how the other macro was called, etc.) that I'd end up passing the value from one macro to the next, and I don't want that: I want it explicitly only in the macro I'm using it in.

With local variables, I can reuse names as much as I want without thinking about where else they might be used in a given set of macros.

-rob.

3 Likes

Yea, instance variables are specifically for sharing variables between macros. Not good as counters. ;p

I see what you mean.
But in that case we are dealing with "probability", right?
The probability of 2 or more macros running at the same time, executing actions that require variables from other macros, and also sharing the exact same instance variable name, is pretty rare if not almost impossible, right?

I'm trying to understand how "dangerous" this can be, especially when there are so many different variable names and I try to make them as "unique" to the macro they are being used in as possible, that the chances of "cross-processing" is so low, that I can see how just using instance variables would seem more advantageous.

At the same time, @Zabobon has some good arguments to how Local instances and subroutines seem to be more than enough for most macros.

If Macro A calls Macro B, and both use instance_theCounter, then Macro B will see the value from Macro A, which may or may not be an issue depending on how it's used. And a lot of my macros are really just one controlling macro that calls 10 to 20 sub-macros, so for me, it's a very real concern. I use local whenever possible, instance on an occasional basis, and global almost never.

-rob.

Yes, in that particular case, the variable name seems to be something you use a lot as the default.
I always try to add relatable names for example if the counter is about "oranges" I would make my variable "Instance__orangesCounter", that's why I was saying that the chances of that happening, are pretty low, at least on my personal workflow.

At the same time, in 2+ years of using KM I never felt the need to use instance variables anyway, so...
And now that I understand how Subroutines work, I think that will be my next adventure. Maybe with that, instance variables are not as necessary?

But I can see what you mean and thanks for sharing your workflow. It's alway good for me to see how others work.

I'm about to go on a soapbox here, so pardon my pontificating:

It's almost never a good idea to disregard a potential problem based on the likelihood of it happening. The exceptions are 1) if the unexpected thing happens, you're notified of it, which is fine, and 2) coding to prevent/detect the unlikely event is just more trouble than it's worth.

So the rarity of a collision of variables happening shouldn't factor into your coding to prevent it, when it's easy to prevent it. And if it ever did happen, your macros would act in an extremely odd way, with you having no idea whay happened.

Ever have one of those "it only happens every once in a while, and I can't duplicate it" types of problems? Yeah, not much fun at all.

1 Like

On the other hand, a subroutine parameter is documentation as to what's expected. Either way is fine of course - just talking this out.

1 Like

I completely agree.
Sometimes when I ask these questions, is not so much about me assuming that I will do it this or that way, because I think it's better. I usually ask them just so I can understand the various end results and why people would do it this way instead of that way. I totally agree that it's better to use the tool that will prevent issues in the future and as I mentioned, my variable names are always as "unique" as possible, even if they are Local variables and are not prone to errors like the one we are talking about, exactly because of that, even if the name end up being "too long".

That being said, knowing how others approach the different tools is always fascinating to me, because I'm a "sponge" when it comes to knowledge. And I love challenging how others work, just because I love seeing how that sometimes shifts the perspective :slight_smile:

And today I really learned a lot, which is great! Thanks!

1 Like

One thing I learned over the years is that most of the times we just learn by doing it. Theory is great, but then you have those moments of "oh ok, now I understand why this approach no longer makes sense" :wink:

That's really the only way I learn most things. Theory is great, but if I don't have any experience with it, it doesn't stick. In this case, for me, seeing is understanding.

1 Like

And when your "OrangeCounter" gets spun out into a sub-macro it'll carry on working, which is great. You then have to count the number of oranges in each of multiple crates, so you put that sub-macro into a "For Each", remembering to reset the instance variable to 0 when each crate is "opened", and all is still good.

And then the number of crates increases so much that the only way you can finish on time each day is to count the contents of multiple crates at the same time, so you set your sub-macro to "Asynchronous" and... All your counts are coming out wrong.

Which sounds like a real reach, just to make a point -- but something similar to the above has happened so often in software development. And your macros are software, and they will develop over time, so it's worth practicing avoidance tactics now! And one of those tactics is to "scope your variables as tightly as you can, and only loosen if you must". So always default to Local_, and only spread out to Instance_ and Global_ if you need to.

Recursion. You can't use Instance variables in a macro that uses recursion. That's because each recursion needs to have access to its own variables.

(I didn't read all the posts in this thread, but I did a search and couldn't find the string "recur".)

Yes, I have used recursion in a macro when I was trying to process a string with nested parentheses.

1 Like