• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

What exactly is the With-statement doing behind the scenes?

A

atmobeat

Guest
Greetings GameMakers! I'm curious what exactly the with statement is doing behind the scenes. Is what is going on behind the scenes in GMS2 when we use "with(obj_pushable)" amount to looping through all instances and checking if object_index == obj_pushable? Then how does it make each instance execute the rest of the code?

I like using inheritance, especially along with the with-statement, but what I currently want to do is impossible with simple parent-child inheritance (I would love a simple component system that works basically just like the current system, just with multiple "parents"). So I'm trying to understand it all a bit better.
 

GMWolf

aka fel666
First let me preface by saying no one outside YYG, or ex YYG employees really know what GM is doing. I can only make educated guesses.

Is what is going on behind the scenes in GMS2 when we use "with(obj_pushable)" amount to looping through all instances and checking if object_index == obj_pushable?
Pretty much. It might keep around lists of instances for each type so that it doesn't have to iterate and check through each instance.

Then how does it make each instance execute the rest of the code?
Saying that instances execute code is a bit of a shortcut, and handy way to think about code.
I'm reality, of course, your cpu is executing the code.
What GM likely does, is keep a global 'running_instance' variable that denotes what the current instance is (accessible through the 'id' variable in GML).
Then when you read/write variables, or use certain functions it checks what the running_instance variable is, and applies the change to that instance.

A 'with' block iterates through the instances that match the request, sets the running_instance variable for each, and runs the code.
Then it sets the variable back to what it was before the with block. (It might do that with a stack)

I like using inheritance, especially along with the with-statement, but what I currently want to do is impossible with simple parent-child inheritance
Shoot! Maybe we can come up with an alternative solution!
(I would love a simple component system that works basically just like the current system, just with multiple "parents").
Yeah, GM being dynamic and all, I don't think you would end up with the diamond problem.
Though it would probably be best if they kept the single INHERITANCE (to inherit events), but introduced tags maybe.
So you could tag an object as "pushable", and then iterate through all "pushables".
Hmm, this is giving me an idea actually...
 
Last edited:

Simon Gust

Member
First let me preface by saying no one outside YYG, or ex YYG employees really know what GM is doing. I can only make educated guesses.


Pretty much. It might keep around lists of instances for each type so that it doesn't have to iterate and check through each instance.


Saying that instances execute code is a bit of a shortcut, and handy way to think about code.
I'm reality, of course, your cpu is executing the code.
What GM likely does, is keep a global instance_id variable that denotes what the current instance is.
Then when you read/write variables, or use certain functions it checks what the instance_id variable is, and applies the change to that instance.

A 'with' block iterates through the instances that match the request, sets the instance id variable for each, and runs the code.
Then it sets the variable back to what it was before the with block. (It might do that with a stack)


Shoot! Maybe we can come up with an alternative solution!

Yeah, GM being dynamic and all, I don't think you would end up with the diamond problem.
Though it would probably be best if they kept the single INHERITANCE (to inherit events), but introduced tags maybe.
So you could tag an object as "pushable", and then iterate through all "pushables".
Hmm, this is giving me an idea actually...
Not many know this and you didn't say anything About it, but there is actually a built-in Array that holds all active instance ids. It's called instance_id[].
 

GMWolf

aka fel666
Not many know this and you didn't say anything About it, but there is actually a built-in Array that holds all active instance ids. It's called instance_id[].
Wow cool, I didn't even realize that!

So, when I used instance_id in my post above, I didn't mean the actual instance_id variable that exists, but another one, 'running_instance' or whatever. I'll edit above to avoid confusion.
 

curato

Member
I guess it really depends on what exactly your are trying to achieve. if you are literally trying to push every pushable object on the level at one time then with is a pretty good way to loop through them all, but if for example if you were going to drop a bomb and only wanted the push away the objects in range of the blast it may be more effective to use a collision_circle and let each instance handle the collision specifically themselves.
 
A

atmobeat

Guest
Sorry for the slow response @GMWolf but it was a kind of holiday here where I am so I've been relaxing a bit.

Saying that instances execute code is a bit of a shortcut, and handy way to think about code.
I'm reality, of course, your cpu is executing the code.
What GM likely does, is keep a global 'running_instance' variable that denotes what the current instance is (accessible through the 'id' variable in GML).
Then when you read/write variables, or use certain functions it checks what the running_instance variable is, and applies the change to that instance.
Great info and ya I was speaking abstractly in my question.


It might keep around lists of instances for each type so that it doesn't have to iterate and check through each instance.

A 'with' block iterates through the instances that match the request, sets the running_instance variable for each, and runs the code.
Then it sets the variable back to what it was before the with block. (It might do that with a stack)

Yeah, GM being dynamic and all, I don't think you would end up with the diamond problem.
Though it would probably be best if they kept the single INHERITANCE (to inherit events), but introduced tags maybe.
So you could tag an object as "pushable", and then iterate through all "pushables".
Hmm, this is giving me an idea actually...

Shoot! Maybe we can come up with an alternative solution!
I'd love to come up with something with you (your tutorials have already been a great help to me in learning my way around GMS). Even just your comments in this post makes me think it would not be difficult at all to come up with something that functions exactly how I want it. In fact, the only thing I disagree with you about is including events in some form of multi inheritance. That seems exceptionally powerful to me with the caveat that you need to be careful you don't code yourself into the diamond problem. Since parenting in GM is basically just copy/pasting code into children's events, I just don't understand why inheritance HAS to be single inheritance in GM. Here's the beginning of a pretty simple (and lightweight?) strategy to introducing multi-inheritance in GM:

1. Have a singleton object called something like 'obj_components'
2. Have a bunch of lists in obj_components that instances in your game can add themselves to (e.g. list_pushables, list_characters, list_pickups but really the things you can't get to fit the single-inheritance parent/child hierarchy since you should just use that if you can)
3. Next have a parent object called something like 'par_multi_inheritor'
4. In each of par_multi_inheritor's step events just have a check to see if the child instance is in obj_components.list_pushables. If so, then run some code that you want all pushables to run for that event. Do the same for each other event as needed.

If all the things in your game that you want to have multiple inheritance can be a child of par_multi_inheritor, then that would cover the copy/paste part of the parent/child hierarchy without the restriction of single-inheritance. You could even have a list_non_inheritor that you add instances to that don't need any of the components, and just have a check at the beginning if the instance running the code for that event is in list_non_inheritor. If it is, then continue on, else do all the checks to see which components the instance has (i.e. which lists it is in). Some kind of optimization like this may be nice to skip unnecessary checks.

Your with-statements would have to be a bit different for any pushable (i.e. anything in list_pushables). So if you wanted to run some code on all your pushables, you would just loop through the instances in list_pushable and run the with-statement on each of the instances individually. Like so

Code:
var listSize = ds_list_size(obj_components.list_pushables)
for(var i = 0, i < listSize, ++i)
   {
   currentInstance = ds_list_find_value(list_pushables, i)
   with (currentInstance)
      {
      code here
      }
   }
Obviously, GM's built-in parent/child stuff is still very useful, especially when you want to use its built-in functions with parents like place_meeting(x, y, par_impassable).

Is that all there is to it? Am I forgetting something obvious, or does that capture most of the power of parent/child inheritance but allow for multi-inheritance?
 
A

atmobeat

Guest
I guess it really depends on what exactly your are trying to achieve. if you are literally trying to push every pushable object on the level at one time then with is a pretty good way to loop through them all, but if for example if you were going to drop a bomb and only wanted the push away the objects in range of the blast it may be more effective to use a collision_circle and let each instance handle the collision specifically themselves.
Should have multi-quoted this in my last post but forgot. You probably wouldn't want to move all pushables at once, but you may want all pushables to check if they are within a certain region or over nothingness or something else. The point isn't specifically about using inheritance with pushables. It's the general idea that with-statements are useful with parent objects.

Here's maybe a better example. In my game I have "active" objects that my depth-sorter has to resort each step because they can change their y-position in the game and "static" objects in my game that only sort themselves once in their create event since they don't need to ever be resorted since they don't move. But I can't use the parent child system in GMS2 because I really need to use parent objects for my impassable objects and passable ones for collision, but I have active and static impassable objects and active and static passable objects. So I can't have an active parent object and static one. Also, I can't say with(par_active) do stuff. I have to do something else that isn't as elegant. I would like to have some form of multi-inheritance and the response above to GMWolf is an attempt to implement that. I want things that can be a child of par_impassable and include the active component or include the static component, and I want things that can be a child of par_passable and include the active component or the static component. I'd also like to be able to use the with-statement on instances that have the active component or instances that have the static component. And I'd really like to do this without having a ton of instances as some of the entity-component systems I've seen use a TON of GameMaker objects to do their thing.
 

GMWolf

aka fel666
1. Have a singleton object called something like 'obj_components'
2. Have a bunch of lists in obj_components that instances in your game can add themselves to (e.g. list_pushables, list_characters, list_pickups but really the things you can't get to fit the single-inheritance parent/child hierarchy since you should just use that if you can)
3. Next have a parent object called something like 'par_multi_inheritor'
4. In each of par_multi_inheritor's step events just have a check to see if the child instance is in obj_components.list_pushables. If so, then run some code that you want all pushables to run for that event. Do the same for each other event as needed.
What you just described sounds similar to composition in an entity component system, just less powerful.
It's not quite the same as inheritance because you have a clear controller object that applies a function to all objects, so it's much easier to debug than inheritance.

Here's maybe a better example. In my game I have "active" objects that my depth-sorter has to resort each step because they can change their y-position in the game and "static" objects in my game that only sort themselves once in their create event since they don't need to ever be resorted since they don't move. But I can't use the parent child system in GMS2 because I really need to use parent objects for my impassable objects and passable ones for collision, but I have active and static impassable objects and active and static passable objects. So I can't have an active parent object and static one. Also, I can't say with(par_active) do stuff. I have to do something else that isn't as elegant. I would like to have some form of multi-inheritance and the response above to GMWolf is an attempt to implement that. I want things that can be a child of par_impassable and include the active component or include the static component, and I want things that can be a child of par_passable and include the active component or the static component. I'd also like to be able to use the with-statement on instances that have the active component or instances that have the static component. And I'd really like to do this without having a ton of instances as some of the entity-component systems I've seen use a TON of GameMaker objects to do their thing.
Sounds like all you need are two lists:
One for sortables and another for non sortables.
Then your instances can have a 'passable' variable.

Thats probably the better option long term too, makes it trivial to add a new list, etc.

Inheritance is better to describe behaviour, not lists of instances. (Lists represent lists pretty well, turns out ;))
 
A

atmobeat

Guest
What you just described sounds similar to composition in an entity component system, just less powerful.
It's not quite the same as inheritance because you have a clear controller object that applies a function to all objects, so it's much easier to debug than inheritance.

Sounds like all you need are two lists:
One for sortables and another for non sortables.
Then your instances can have a 'passable' variable.

Thats probably the better option long term too, makes it trivial to add a new list, etc.

Inheritance is better to describe behaviour, not lists of instances. (Lists represent lists pretty well, turns out ;))
That's kind of what I'm shooting for. I don't know that I need a full-on entity component system but honestly I don't know enough about them at this point to be sure of anything. I agree with the sortable/non-sortable "tags" that I probably just need a couple of lists, especially now that I know how to use that list to run a with-statement on all the instances. But why use a passable variable? That would mean I would have to use the slower instance collision functions (like instance_place) instead of place_meeting, right?

Also, is there a way to get the attention of the yoyo staff without looking like a selfish dick? Like you said, the only people who know how the with-statement works are the ones at yoyogames itself. I'd like to know what the difference is between the following two pieces of code (one using a parent object and one the method discussed above):

Code:
with (obj_sortable)
  {  do stuff   }
and

Code:
var listSize = ds_list_size(global.list_sortables)
for(var i = 0, i < listSize, ++i)
   {
   currentInstance = ds_list_find_value(global.list_sortables, i)
   with (currentInstance)
      {
      code here
      }
   }
 

Mike

nobody important
GMC Elder
First let me preface by saying no one outside YYG, or ex YYG employees really know what GM is doing. I can only make educated guesses.
It's not complicated....

A "with( inst )" or a "with(obj)" basically creates an internal array, then does a FOR loop over the top of it.

If you use an object or parent object, it'll put all the instances of this type in this array then loop over it.
If it's a single instance, just think of it as a loop of 1....
 
A

atmobeat

Guest
If you use an object or parent object, it'll put all the instances of this type in this array then loop over it.
If it's a single instance, just think of it as a loop of 1....
Awesome! Thank you mike. Does everything else that's similar work the same way? Like place_meeting(x, y, obj) and place_meeting(x, y, instance).

EDIT: Although, with objects at least, I guess this kind of pushes the question back one level. How does it choose the things to put in the array? Is it looking at all instances, checking if the instance's object_index == obj_whatever, and building up the array? Or, as GMWolf suggested, is there a more limited set of instances already stashed away somewhere in GM and the array is built up from just the instances in that set?
 
Last edited by a moderator:

Mike

nobody important
GMC Elder
Awesome! Thank you mike. Does everything else that's similar work the same way? Like place_meeting(x, y, obj) and place_meeting(x, y, instance).
These are more complicated as it can obviously only return a single result, so for the most part they're useless, but on the whole yes....
I'd avoid using an object on anything that returns a value, unless it's specifically designed to do so, as you've no idea on the order, or which one will trigger results.
 
Top