GMS 2 Variables

Would someone confirm the only difference between an instance variable and a local variable 'var' is that variables initialized with var can't be accessed from outside? I have complete several projects with GM now but I have never needed to use local variables. Just instance and global ones. I'm concerned about this because I want to optimize.

Would it be fair to say that...

1) if a variable needs to be accessed from outside the object instance should be instant or global
2) local variables are more system efficient
3) Predefining a variable size with a function is more efficient (Provided you know the size)
4) A global variable like constants, no matter where they are defined gets initialized first.
5) Accessing outside variables with a dot 'this.that' is not as efficient as calling a global or calling a local from itself.
6) Creating a variable with a predefined size creates instance variables.

None of these things stop me from working but some clarity on this would be great. And yes I know there is a manual. :)

Edit: I have a huge number of variables that need to be accessed from outside the object it resides in. For example, I don't use magic numbers, EVER. So my settings object needs to potentially talk to any variable. Colours, sizes, scales, visibility, size limits etc. I can't think of hardly any variables that don't need to be accessed from outside.
 

saffeine

Member
the way i've always understood it, and what i believe to be the case, is that var is specific to the event / code that calls it.
if you use var within a script, it will be able to use the variable the same as any other, but as soon as the script ends it no longer has a reference.

example:
GML:
// scr_test();
var _text = "here is some text.";
show_debug_message( _text ); // prints "here is some text." into the debug console.

// an object's key_press event.
scr_text();
show_debug_message( _text ); // throws an error or an 'undefined', as _text belongs to the script and not to the instance.
global variables: if you want to keep a variable persistent between rooms, or want any object to access it. ( no, they are not initialised first. they're initialised if, when, and where, like any other. see: macros. )
instance variables: if a variable is supposed to only belong to and / or be edited by the object that sets it. ( these can still be accessed as such if you need to: ObjectName.variable. )
local ( var ) variables: if a variable is only supposed to be temporary and will not be accessed outside of the script that declares, defines, and / or compares it.

i hope this answers a few of those questions, but i'd imagine it doesn't answer all of them.
some of them are outside my bubble of knowledge, such as performance and such.
 
Last edited:

Sabnock

Member
Instance variables

A var variable is a temporary variable used only in the host instance and is basically destroyed at the end of each cycle where as a normal variable is stored in memory and can be accessed from any other instance.

Global variables are variables stored in memory and are available to all instances at all times but i really don't use them at all.
 
Last edited:
Do you use var initialized variables halfway through a step event? I do it like this.

1) Global variables are all set in the room to create code. No exceptions.
2) Local variables only initialized in object create code that does not require 'outside access'. No exceptions.
3) Instance variables are created within events and in create code if they need to be accessed from outside.
4) I always set constants in-room create the start before any other code. No exceptions

Does this sound familiar?
 

Sabnock

Member
Do you use var initialized variables halfway through a step event? I do it like this.

1) Global variables are all set in the room to create code. No exceptions.
2) Local variables only initialized in object create code that does not require 'outside access'. No exceptions.
3) Instance variables are created within events and in create code if they need to be accessed from outside.
4) I always set constants in-room create the start before any other code. No exceptions

Does this sound familiar?
you can declare all of your local variables at the start of an event like this
GML:
var _variable1, _variable2, _variable3;
or you can declare them as you go like this
GML:
var _rotate = keyboard_check(vk_left) - keyboard_check(vk_right);

facing_angle += _rotate * rot_spd;
if (facing_angle < 0) facing_angle = 359;
if (facing_angle > 360) facing_angle = 0;

var _move = keyboard_check(vk_up);

if (_move != 0 && spd < max_spd) {
    hspd += dcos(facing_angle) * thrust;
    vspd += -dsin(facing_angle) * thrust;
  
    if (!audio_is_playing(snd_thrust)) audio_play_sound(snd_thrust, 0, false);
}

x += hspd;
y += vspd;
 
Edit: I have a huge number of variables that need to be accessed from outside the object it resides in. For example, I don't use magic numbers, EVER. So my settings object needs to potentially talk to any variable. Colours, sizes, scales, visibility, size limits etc. I can't think of hardly any variables that don't need to be accessed from outside.
So I want to manipulate a few items in a list that could be any size at this point.
Code:
var _list_size = ds_list_size(my_list);
for (var i=0;i<_list_size;i++) {
   var item = my_list[| i];
   item.speed = 5;
   var x1 = item.x;
   var y1 = item.y;
   var x2 = x1+item.sprite_width;
   var y2 = y1+item.sprite_height;
   draw_rectangle(x1,y1,x2,y2,true);
}
Etc. You get the point, using local variables here is not only faster (apparently, GMS fetches the ds_list_size every iteration if it's used in the setup of the for loop: for (var i=0;i<ds_list_size(my_list);i++), while using a local var it only fetches it once), but I don't have to have a bunch of instance variables set up for x1, y1, item, etc. If I used instance variables for those values, I might be altering something in another code block in that instance unintentionally (if item were a instance variable then when that for loop finished running, item would always be set to whatever is in the last slot of my_list, and that might alter something else I'm doing with item in the Step event, let's say).

Plenty of reasons to use local variables, literally no reasons not to (unless you consider 'not understanding the scope and therefore borking things' a reason not to, which you shouldn't).
 

Nidoking

Member
More importantly, a local variable is scoped to the event or script (or function) where it's declared, not to any instance. This is important when you're working with "with" constructions:

GML:
var counter = 0;
with (obj_accumulator)
{
  counter += amount;
}
This will add the instance-scoped "amount" variable of every obj_accumulator into the local "counter" variable.
 

saffeine

Member
Do you use var initialized variables halfway through a step event? I do it like this.

1) Global variables are all set in the room to create code. No exceptions.
2) Local variables only initialized in object create code that does not require 'outside access'. No exceptions.
3) Instance variables are created within events and in create code if they need to be accessed from outside.
4) I always set constants in-room create the start before any other code. No exceptions

Does this sound familiar?
i use var initialised variables for any block of code that i have where i don't want the variable to be permanent.
for example, if i'm calculating the distance between two points and don't need to know that distance later, i use var.

1. global variables are usually set at the start of a game or room, yes. there could be exceptions but i can't think of any, since if a variable is going to be global, it's implied that it's going to be used later by many objects.
2. local variables can be used anywhere. i use them in all of my scripts, all of my temporary blocks of code ( like movement, to calculate how far to move ), and other such things where i don't want / need the variable later.
3. instance variables can also be used anywhere. rather than setting them at a start of a room though, they're usually in the create event, yes. they can be set elsewhere but again, i can't think of an exception that would do this.
4. that's good practice. constants / #macros should be set right at the beginning of anything, and i think gamemaker compiles them before everything else anyway, so you don't need to worry too much.
 

FrostyCat

Member
1) if a variable needs to be accessed from outside the object instance should be instant or global
2) local variables are more system efficient
3) Predefining a variable size with a function is more efficient (Provided you know the size)
4) A global variable like constants, no matter where they are defined gets initialized first.
5) Accessing outside variables with a dot 'this.that' is not as efficient as calling a global or calling a local from itself.
6) Creating a variable with a predefined size creates instance variables.
1: Yes.
2: Yes, but only slightly. The main point of local variables is correctness, efficiency is only a minor side effect.
3: What is predefining a variable "size"? GML is not a static-typed language.
4: You're talking about macros, not global variables. Global variables only get initialized when the line saying global.something = ...; gets to run.
5: Yes.
6: Wrong. The scope of a variable depends on the syntax used to set it up (global.xxx for for global variables, yyy for instance variables, var zzz for local variables), not what you assign to it.

Would someone confirm the only difference between an instance variable and a local variable 'var' is that variables initialized with var can't be accessed from outside? I have complete several projects with GM now but I have never needed to use local variables. Just instance and global ones. I'm concerned about this because I want to optimize.
Stop, really. This belief is as wrong-headed as it is dangerous. If you've completed several GM projects and never felt you needed to use local variables, it's because you should have been using them but didn't bother to. And it's more than optimization or a matter of taste.

There is this myth around here about how you only need global and instance scope, and that local variables are an "optimization". If you've been using GM without local variables, you've been using it wrong this whole time. Using local variables is not a matter of optimization or style, it is a matter of correctness. It keeps temporary variables from accidentally talking to each other and to instance/global variables, and as also mentioned, a key part of using with blocks effectively.

If you want to talk efficiency, look at the instance scope of any script-running instance in your var-free projects. You will find loads of residual variables from scripts and loops that it has run from the past, making it a chore to wade through in the debugger and taking up memory past the time where it's relevant. And the more scripts and loops there are, the more the instance scope gets filled with clutter that are not genuine instance properties.

But the genuine danger comes from when variables that shouldn't talk to each other unexpectedly do, simply because you didn't use local scope when you should. This post from 3 years ago is as relevant today as ever, and I strongly urge you to read and try out the counterexamples in it.

Local variables for temporary values. Instance variables for individual properties. Global variables for singular, environment-wide properties. This should be taught from day one and strictly enforced, not dismissed as mere optimization or a matter of taste.
 
You mean if you wanted to use with but not want to access all instances or child objects perhaps. I have used with before only using instance variables without a problem. This is why I'm trying to tidy up now to avoid confusion and maybe even disaster later on.

Thanks for everyone's help.
 
Thanks for clearing things up. I'm in constant fear of not doing this correctly. Mainly because if there is something wrong GMS generally lets you get away with it.

Are there any GMS extensions that force coding standards? I believe when I was using .NET some years ago there was something called style cop or something similar. That would be a great help if such a thing existed.
 
Last edited:
1: Yes.
2: Yes, but only slightly. The main point of local variables is correctness, efficiency is only a minor side effect.
3: What is predefining a variable "size"? GML is not a static-typed language.
4: You're talking about macros, not global variables. Global variables only get initialized when the line saying global.something = ...; gets to run.
5: Yes.
6: Wrong. The scope of a variable depends on the syntax used to set it up (global.xxx for for global variables, yyy for instance variables, var zzz for local variables), not what you assign to it.


Stop, really. This belief is as wrong-headed as it is dangerous. If you've completed several GM projects and never felt you needed to use local variables, it's because you should have been using them but didn't bother to. And it's more than optimization or a matter of taste.

There is this myth around here about how you only need global and instance scope, and that local variables are an "optimization". If you've been using GM without local variables, you've been using it wrong this whole time. Using local variables is not a matter of optimization or style, it is a matter of correctness. It keeps temporary variables from accidentally talking to each other and to instance/global variables, and as also mentioned, a key part of using with blocks effectively.

If you want to talk efficiency, look at the instance scope of any script-running instance in your var-free projects. You will find loads of residual variables from scripts and loops that it has run from the past, making it a chore to wade through in the debugger and taking up memory past the time where it's relevant. And the more scripts and loops there are, the more the instance scope gets filled with clutter that are not genuine instance properties.

But the genuine danger comes from when variables that shouldn't talk to each other unexpectedly do, simply because you didn't use local scope when you should. This post from 3 years ago is as relevant today as ever, and I strongly urge you to read and try out the counterexamples in it.

Local variables for temporary values. Instance variables for individual properties. Global variables for singular, environment-wide properties. This should be taught from day one and strictly enforced, not dismissed as mere optimization or a matter of taste.
Excellent link thank you.
 
That was a great article and agree completely. Particularly with game maker, sometimes people are professionals and have come from other languages and don't know the IDE or the syntax. Sometimes people don't know how to phrase the question or are misunderstood or even don't know how to phrase the question. On top of that people have different coding styles and find examples that don't comply with there own methods harder to interpret.

Maybe the person asking the question knows more but yet different things to the person answering.

Great stuff. Thanks.

Edit: I know you were talking to 'sabnock'. but I appreciate this because you are correct in your summation.
 
Last edited:
So I've been tidying up my code I have found a few case uses (reason to use them not switch statements). I'm still a little confused. For example, in the manual, it uses var for loops. I don't understand why. Yes, it's destroyed as soon as it's used but it just needs to recreate it again next 'step'. The only reason I can see for utilizing a local 'var' variable in a loop is if it's in the create event.

I know I'm missing something but I can't put my finger on it.
 

TsukaYuriko

šŸŒ 
Forum Staff
Moderator
Simply put, because it doesn't need to exist anymore. It'll keep the variable used in the loop around as an instance variable with the value of whatever the highest loop during the last step was. This could, for example, clutter up the debug view of that instance with useless variables. Keeping it will also use up memory. With a single instance, this makes no noticeable difference, but it scales linearly the more such instances you have, and the more such loops you're using, although in most cases, it still won't amount to much... that is, unless you're dealing with hardware that is severely memory-limited, which may actually still be the case nowadays, e.g. mobile targets.

For these reasons and potentially more, it's considered bad practice to keep stuff in memory that you don't have to.
 

Sabnock

Member
So I've been tidying up my code I have found a few case uses (reason to use them not switch statements). I'm still a little confused. For example, in the manual, it uses var for loops. I don't understand why. Yes, it's destroyed as soon as it's used but it just needs to recreate it again next 'step'. The only reason I can see for utilizing a local 'var' variable in a loop is if it's in the create event.

I know I'm missing something but I can't put my finger on it.
To quote FrostyCat
If you've completed several GM projects and never felt you needed to use local variables, it's because you should have been using them but didn't bother to. And it's more than optimization or a matter of taste.

There is this myth around here about how you only need global and instance scope, and that local variables are an "optimization". If you've been using GM without local variables, you've been using it wrong this whole time. Using local variables is not a matter of optimization or style, it is a matter of correctness. It keeps temporary variables from accidentally talking to each other and to instance/global variables, and as also mentioned, a key part of using with blocks effectively.

If you want to talk efficiency, look at the instance scope of any script-running instance in your var-free projects. You will find loads of residual variables from scripts and loops that it has run from the past, making it a chore to wade through in the debugger and taking up memory past the time where it's relevant. And the more scripts and loops there are, the more the instance scope gets filled with clutter that are not genuine instance properties.
 
Step event:
Code:
for (i=0;i<number;i++) {
   if (i == 5) {
      check_inventory(i);
   }
}
check_inventory script:
Code:
inv_item = argument0;
for (i=0;i<inv_size;i++) {
   if (i == inv_item) {
      delete_inv(i);
   }
}
Can you see a problem here? It's pretty obvious when laid out like this, but this exact same scenario can bite you on the arse any number of subtle ways that will potentially take hours or days to debug. If you make i a local variable using var, then there's no problem at all and the scripts can run like this. If you don't do this, you have to keep using different letters or even start using actual words as the incrementer variables and you also have to hope that you don't accidentally forget that you've already assigned a particular letter/word to a particular increment and reuse it somewhere, otherwise the above can happen.

The same thing for inv_item in this case. It's a comfortable term to use for a variable storing an item from your inventory, but what happens if you want a script to modify an item, so you use inv_item, and then later on, you're checking a variable called inv_item in another event?

I dunno how to properly explain this better than Frosty. You LOSE access to variable names if you neglect var. Each time you have to come up with something new, or have a potential conflict where you are setting the value of a previously created variable that you DON'T want to set the value of.
 
1) I have modified my scripts to use local variables now whereas before I didn't
2) I use local variables for all loops now whereas before I didn't
3) I use return for scripts now rather than using them as extended code blocks to reduce step or draw code line count (readability) and for reuse in other scripts

Am I still going wrong? I hate to have fundamental misunderstandings. As you stated if you don't it can bite you in the bum real hard.

Edit: Would it be fair to say as a rule of thumb. Never use instance variables inside a script.
 

chamaeleon

Member
3) I use return for scripts now rather than using them as extended code blocks to reduce step or draw code line count (readability) and for reuse in other scripts
This seems like taking it too far. Scripts are an excellent way encapsulating behavior that is shared, whatever the purpose may be. There's nothing wrong with having a script that performs some action rather than just returning values, just like in any other programming language.
 

TheouAegis

Member
Edit: Would it be fair to say as a rule of thumb. Never use instance variables inside a script.
There is no "never use". Global variables have their uses. Local variables have their uses. Instance variables have their uses. If the instance calling a script that uses instance variables doesn't already have said instance variables, GM will either throw an error when trying to read the variable or create the variable in the instance if trying to write to it. If the instance already has the variable, the script will run no problem. Instance variables are commonly used in scripts, since a script is just code meant to be used by multiple objects.
 
Thanks for that. I'm constantly aiming to make objects as self-contained as humanly possible. I don't know if this is the right way to think about it or not but it makes it easier to think about and easier to import to other projects. I don't like to integrate objects wherever possible. I like to plug in a number and get a number out then it's dying.

It's the when to use them for what use is my problem. Although I believe I have hammered most of the confusion out in the past couple of days with everyone's help.

Variables aside. My biggest worry is thinking I understand something but I don't'. Or at least don't know enough.

When I started first programming all those years ago I didn't even know you could have things like case statements 'switch' and ended up with thousands of lines of code. I don't like not knowing it disturbs me. Even if it appears to be fine I get the feeling that somthing isn't quite clicking.

Thanks again.
 

Nidoking

Member
One of the main considerations for variable scope, and this overlaps with setting up your parents/inheritance structure, is understanding more complex data types and what they're useful for. Instance variables should always tell you something important about the instance. HP, color, speed, state - all of these are properties of an instance that should be scoped to the instance. Loop indices don't tell you anything about an instance - they're just markers for how many times you've run the loop. So they should be scoped to a script or event and not preserved after that. Likewise, if you're temporarily assigning a name to something you pull out of a data structure (for example, grabbing something from a list and then doing things with it), that's also a good case for script scope.

However, there are very good cases for scripts to refer to instance variables. Suppose you make a script that resolves an attack and decreases the HP of the affected enemy. The enemy would be one of the arguments. Assuming that this enemy instance has an HP value, you can use .HP to get or set it. For this reason, I would ensure that the "HP" variable is defined in a parent object for all enemy types and initialized in the default Create event (or, more often, the Variable Definitions). Now, as long as the argument is an obj_enemy_parent, I know that it has a defined HP value, and that I can do what the script is supposed to do with that value. I don't care what type of enemy it is most of the time, but I know that it has HP. That's the only assumption I intend to make about the contents of the instance I get.
 
I have utilized a parent class palette which basically has a whole ton of properties to how a button set should behave. I won't go into detail but that kind of confirms again I am on the right track with what I have been writing. If possible I would like to upload a small(ish) code sample to confirm that I am doing this correctly. I will have to trim it down for the example somewhat because time is precious, much appreciated by the way.

I believe we are on the same page.

Thank you all again.
 
show_debug_message(is_string("true")); = 1;
show_debug_message(is_real(1)); = 1;

show_debug_message(is_bool(true)); = 0; (Totally confused about this)

Is the only way to make something boolean to take a number and convert it. test = bool(1); is_bool(test);
 

chamaeleon

Member
show_debug_message(is_string("true")); = 1;
show_debug_message(is_real(1)); = 1;

show_debug_message(is_bool(true)); = 0; (Totally confused about this)

Is the only way to make something boolean to take a number and convert it. test = bool(1); is_bool(test);
Yes, that is my understanding, for whatever implementation reasons of the GMS compiler and runtime. @FrostyCat has mentioned that he does this in particular in order to deal more exactly with JSON content which can have true/false values, distinct from using using 0 or 1.

Next up, you'll wonder how useful ds_exists() is: https://forum.yoyogames.com/index.php?threads/is-it-possible-to-get-all-instance-variables-as-ds_map.70500/post-417151
 
I did have that problem the other day but that was my fault because I forgot I had some lists stored in an array.

I have also discovered a defined variables section under the IDE. How useful is this? It doesn't display variables(data types) written in code. However, you do have the benefit of defining them. Is this just another way of doing it because I wouldn't want to open this IDE dialogue every time I want to check if I have defined a variable.

Sorry, that was ever so slightly off-topic but I have just discovered this.

The question is why use 'IDE' pre defined variables. I like to code as much as I can. I don't even use the room editor to place objects or create layers.
 

chamaeleon

Member
I have also discovered a defined variables section under the IDE. How useful is this? It doesn't display variables(data types) written in code. However, you do have the benefit of defining them. Is this just another way of doing it because I wouldn't want to open this IDE dialogue every time I want to check if I have defined a variable.
It can be very useful for. It gives you a visual clue what instance variables are "important" enough to warrant having an editing section set aside for them. Say you add buttons in a menu system. You can define some variables for the object that contains text and a button id (code-related, perhaps having an enum value perhaps, an enum type you might have a switch over in the object code), and when you add an instance to the room, just open up that variable section and you know immediately which instance variables you should give unique values to without having to jump into scripts or event code. So they are not necessarily for all instance variables. You can use it for doors leading to different rooms. Instead of jumping back and forth between code and room editor, you simply double-click on the instance in the room editor, and open up the variable list and you can immediately see which value you set as the destination and it is visually correlated to where the instance is in the room so you can see if it makes logical sense, etc. In short, it's a tool you can use as much or as little as you want. :)
 

Yal

šŸ§ *penguin noises*
GMC Elder
Defined variables can be set in the Room Editor on a per-instance basis, so they're useful for objects like NPCs where you want to set them to complicated values, want to make sure that you've set them to a non-default value (and not forgot any variable), or want to limit the possible values (one of the options is a dropdown list of predefined values).

Dunno if anybody mentioned this yet, but var variables are global scope for the code block they're in, so they're really useful if you use nested with loops (and batch object operations in general) to go through a lot of objects looking for something. You don't strictly need to make variables temporary in most cases, but it saves a bit of memory (and thus speed) per-instance.

Another important caveat: if you don't make loop counters and placeholders vars with nested scripts, the inner script will overwrite the outer script's values for them, and this can lead to all sorts of weird bugs. I've had some issues with this because I often use the same variable names for loop counters and throwaway instance references, and in scripts specifically I try to make everything a var unless the script sets up instance variables as part of initializing a per-instance system.
 
Top