Pages: 1
  Print  
Author Topic: function error  (Read 1714 times)
Offline (Unknown gender) legendarysnake
Posted on: April 21, 2014, 09:02:30 AM
Member
Joined: Apr 2014
Posts: 7

View Profile Email
getting error with functions "execute_string" and "variable_local_exists"
Logged
Offline (Unknown gender) TheExDeus
Reply #1 Posted on: April 21, 2014, 09:37:52 AM

Developer
Joined: Apr 2008
Posts: 1872

View Profile
Because they don't exist. While "variable_local_exists" is possible, but inefficient (because that would require storing all variable names as strings in the code) we don't see a real use for it. execute_string also will probably never going to be supported. We since the beginning (like GM:S until recently) use compiled C++ for the games. So we don't have any parser or JIT compiler to execute code on the fly. If you want scripting in a game, then maybe a Lua extension could be made.

Both of these functions are the "Dark side" of coding though - if you think you need them for something, then most probably you don't. They allow large security holes (like using registry_ functions in the execute_string), crashes and bugs.
Logged
Offline (Unknown gender) legendarysnake
Reply #2 Posted on: April 21, 2014, 10:40:47 AM
Member
Joined: Apr 2014
Posts: 7

View Profile Email
var xch,spr_frame,spr_head,spr_body;
if (image_xscale == 1) xch = floor(x);
if (image_xscale == -1) xch = ceil(x);
spr_frame = sprite_get_name(sprite_index)+'_frame';
spr_head = sprite_get_name(sprite_index)+'_head';
spr_body = sprite_get_name(sprite_index)+'_body';
spr_frame = execute_string('spr_frame='+spr_frame);
spr_head = execute_string('spr_head='+spr_head);
spr_body = execute_string('spr_body='+spr_body);

how it would be replacing execute_string?
Logged
Offline (Unknown gender) TheExDeus
Reply #3 Posted on: April 21, 2014, 01:08:40 PM

Developer
Joined: Apr 2008
Posts: 1872

View Profile
Quote
var xch,spr_frame,spr_head,spr_body;
if (image_xscale == 1) xch = floor(x);
if (image_xscale == -1) xch = ceil(x);
spr_frame = sprite_get_name(sprite_index)+'_frame';
spr_head = sprite_get_name(sprite_index)+'_head';
spr_body = sprite_get_name(sprite_index)+'_body';
spr_frame = execute_string('spr_frame='+spr_frame);
spr_head = execute_string('spr_head='+spr_head);
spr_body = execute_string('spr_body='+spr_body);

how it would be replacing execute_string?
That code doesn't even make sense, because "spr_head = execute_string('spr_head='+spr_head);" would make spr_head = 0 (execute_string() by default return 0). But why can't you just do this?:
Code: [Select]
spr_frame = spr_image_frame;
spr_head = spr_image_head;
spr_body = spr_image_body;
There are many ways you could do this better. Like create a script for each different "model" and on init just run a specific script (which can be dependent on sprite_index if you want), like:
Code: [Select]
//scr_init_alien - Script for sprite_index = "alien"
spr_frame = spr_alien_frame;
spr_head = spr_alien_head;
spr_body = spr_alien_body;
And in create event:
Code: [Select]
switch (sprite_index){
  case spr_alien: spr_init_alien; break;
}

Another method if you really want to do it this way is using sprite_get_name() in a loop. Like:
Code: [Select]
//scr_find_sprite_from_string(sname) - I love very long function names like these :D
var i;
i=1;
while (true){
var sprite;
sprite = sprite_get_name(i);
if (sprite == "<undefined>") return -1;
if (sprite == argument0){
return i;
}
i+=1;
}
Then you can do scr_find_sprite_from_string(sprite_get_name(sprite_index)+'_head'). You should be fine if you use this only when loading or on create. But doing this per-step would be quite slow. And there is no valid reason you should do it per step.
Logged
Offline (Male) Goombert
Reply #4 Posted on: April 21, 2014, 01:53:38 PM

Developer
Location: Cappuccino, CA
Joined: Jan 2013
Posts: 3110

View Profile
Harri execute_string does return a value, I just tested the following in GM8.1
Code: (EDL) [Select]
show_message(string(execute_string("return 50;")));And sure enough I got a message back with "50" in it. The behavior is just not documented I guess.

http://enigma-dev.org/docs/Wiki/Execute_string
http://enigma-dev.org/docs/Wiki/Execute_file

They work similar to script execute.

http://enigma-dev.org/docs/Wiki/Script_execute
« Last Edit: April 21, 2014, 01:56:23 PM by Robert B Colton » Logged
I think it was Leonardo da Vinci who once said something along the lines of "If you build the robots, they will make games." or something to that effect.

Offline (Unknown gender) TheExDeus
Reply #5 Posted on: April 21, 2014, 03:47:05 PM

Developer
Joined: Apr 2008
Posts: 1872

View Profile
Quote
Harri execute_string does return a value, I just tested the following in GM8.1
I know it returns a value.
Quote
spr_head = 0 (execute_string() by default return 0)
Assignment on the other hand shouldn't. This should "return spr_head=spr_some_head".
Logged
Offline (Unknown gender) legendarysnake
Reply #6 Posted on: April 22, 2014, 05:13:55 AM
Member
Joined: Apr 2014
Posts: 7

View Profile Email
what i can use instead of variable_local_exists?
Logged
Offline (Unknown gender) TheExDeus
Reply #7 Posted on: April 22, 2014, 05:50:24 AM

Developer
Joined: Apr 2008
Posts: 1872

View Profile
Right now nothing. You shouldn't even use it. If you use it just for finding out if something is enabled (like if a unit has "attack"), then make a grid, a list or even better - a map - having all these parameters. Just like you would do in any other compiled language like C++ or bytecode Java. Code like "if (variable_exists("variable") == false) variable = 0;" is bad design and shouldn't be used. That is why GM:S also no longer supports execute_string and variable_exists. They made people do bad stuff with it. Especially when things like execute_string ended up being used for sprite index, which was far from what Mark Overmars made it for.
Logged
Offline (Male) Josh @ Dreamland
Reply #8 Posted on: April 22, 2014, 07:40:39 AM

Prince of all Goldfish
Developer
Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2958

View Profile Email
No, Harri; what he's presented is the number one use case for execute_string. We ought to have functions to look up a resource ID by name. It would require eight bytes of memory by default until first call, at which point it'd build a tree for later use, then use it to look up the sprite.

Variables always exist, legendarysnake. In ENIGMA, the instance creation event is performed after the object creation event, so you can override variables set in create from the instance creation code in rooms. That's the only reason people ever need to use variable_local_exists. Otherwise, use a ds_map.
Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Unknown gender) TheExDeus
Reply #9 Posted on: April 22, 2014, 01:31:42 PM

Developer
Joined: Apr 2008
Posts: 1872

View Profile
Quote
No, Harri; what he's presented is the number one use case for execute_string.
I am aware. But that wasn't the original intention for it. Mark would of just made a custom function for that if he thought it was needed.

Quote
We ought to have functions to look up a resource ID by name. It would require eight bytes of memory by default until first call, at which point it'd build a tree for later use, then use it to look up the sprite.
I guess we could. We already store resource names in the exe.

Quote
Variables always exist, legendarysnake. In ENIGMA, the instance creation event is performed after the object creation event, so you can override variables set in create from the instance creation code in rooms. That's the only reason people ever need to use variable_local_exists. Otherwise, use a ds_map.
Do variables also exist if the variables are actually used only in step event for example? Like in step you add "a = 0" and in create you add "if (variable_exists("a") .."? Because that should logically return false. The use case for variable_exists() was to check in other scripts if the object had a specific attribute. Like if I had scripts for buttons, I would make a button_add() script and in it the first line would be (if variable_exists("button_grid")==false button_grid = ds_grid_create(0,0)). So by doing this I wouldn't need to have a button_init() script. And while I did that in GM, I find it a bad thing now. And so in ENIGMA I just add _init() scripts instead.
Logged
Offline (Male) Josh @ Dreamland
Reply #10 Posted on: April 27, 2014, 10:33:28 PM

Prince of all Goldfish
Developer
Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2958

View Profile Email
What I mean is that the memory allocated for the variable exists. It's true that these values can be uninitialized, at least for var/variant. In fact, we attempt to do so now, at the user's option. We could technically allow something like this:

Code: (C++) [Select]
bool variable_initialized(const variant& x) {
  return x.type != -1;
}

This would offer the same functionality, provided the option "treat uninitialized variables as value 0" was not set.I believe we disable that functionality in release mode, presently, but that's not to say we can't undo that. In general, though, I'm opposed to this; I prefer to be able to seamlessly convert var and variant to primitive types. Before that can happen, of course, I will still need to add checking for function calls that only take the var/variant reference. So theoretically, implementing those functions wouldn't harm too much, at that stage. But I still don't encourage the practice.

But to answer your original question, yes, if you are using the local variable a, it still exists, even if you never use it outside the step event. You are able to access it in other objects using object0.a, or whatever.

The use case you give is archaic at best. If you want other entities to assign that for you, which is arguably way too intimiate (but standard, poor practice in GM), then the solution is to set it to -1 in the create event and check that in the script or whatever. In other words, if (button_grid == -1) button_grid = ds_grid_create(0,0);. This is always safe, because the create event is always performed first. So you'll never accidentally overwrite something by setting it to -1 in create.
Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Male) Goombert
Reply #11 Posted on: April 27, 2014, 11:50:29 PM

Developer
Location: Cappuccino, CA
Joined: Jan 2013
Posts: 3110

View Profile
This might be a good time for me to ask Josh, will the following code work in ENIGMA right now?

Code: (EDL) [Select]
var ass = 4;
delete ass;
Logged
I think it was Leonardo da Vinci who once said something along the lines of "If you build the robots, they will make games." or something to that effect.

Offline (Unknown gender) TheExDeus
Reply #12 Posted on: April 28, 2014, 04:30:49 AM

Developer
Joined: Apr 2008
Posts: 1872

View Profile
Quote
the solution is to set it to -1 in the create event and check that in the script or whatever.
But then if I try to make it a "system" (or something akin to a "class"), then I shouldn't make the user set some random inner data structures in their create event. The whole point was that a user includes the scripts and calls button_add(...) in create and buttons_draw(...) in draw. In this case it is better to either set up everything in button_add() (which requires checking if something exists) or to create a button_init() script.
Maybe a better way would be to create a new object like obj_buttons that works like a class. And then when calling button_add() you check whether the object exists and if doesn't, then create it. If it does then add a button to it. But I wanted my scripts to allow adding buttons to many objects (so for each menu I would have a controller object having the buttons).
If we implement C++ classes, then I would probably use those.

Quote
var ass = 4;
delete ass;
That shouldn't even work in C++. You have to use (or in fact only CAN use) delete if you use "new". If you never used new, then using delete is a good way to segfault. It should be something like this:
Code: [Select]
var* ass = new var();
delete ass;
« Last Edit: April 28, 2014, 04:37:44 AM by TheExDeus » Logged
Offline (Male) Goombert
Reply #13 Posted on: April 28, 2014, 04:42:08 AM

Developer
Location: Cappuccino, CA
Joined: Jan 2013
Posts: 3110

View Profile
My mistake, nevertheless, it does not segfault and appears to work Harri, I just tested it.
Logged
I think it was Leonardo da Vinci who once said something along the lines of "If you build the robots, they will make games." or something to that effect.

Offline (Male) Josh @ Dreamland
Reply #14 Posted on: May 11, 2014, 04:43:05 PM

Prince of all Goldfish
Developer
Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2958

View Profile Email
If that works for any reason, it's because it's getting parsed into something entirely different. But it shouldn't even compile...
Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Pages: 1
  Print