• 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!

is_struct() returning an incorrect value

EDIT: I'm running latest beta 306 (I also tested it with beta 300 and the same problem occurred) but at some point previously, it did function correctly as other people are pointing out below, as I've had this code running fine for a long time while working on Alchementalist.

I'm preeeetty sure this is a bug in GMS, so I guess this is more of a PSA, but if I'm actually making a mistake it'd be sweet if someone could point it out.

is_struct() seems to return true when encountering a function within a struct. Here's the codeblock:
GML:
function MyFunction() {
    some_var = 0;
}

MyStruct = {
    Function : method(self,MyFunction)
}

// This works fine, a is equal to false
var a = is_struct(MyFunction);

// This line is the simplest version of the problem, b equals true here
var b = is_struct(MyStruct.Function);

/* These lines below are the smallest "production" version of what I'm doing, pulling all the stuff out of a struct and checking to see
what each thing is, in this case both is_struct() AND is_method() will return true (i.e. c and d both equal true) */
var _names = variable_struct_get_names(MyStruct);
var _i = 0;
var c = 0;
var d = 0;
var _source = MyStruct;
repeat(array_length(_names))
{
    var _name = _names[_i];
    var _value = variable_struct_get(_source, _name);
    if (is_struct(_value)) {
        c = true;
    }
    if (is_method(_value)) {
        d = true;
    }
}
show_debug_message("A is "+string(a)+", B is "+string(b)+", C is "+string(c)+", D is "+string(d));
First, we create a the function MyFunction(). Then we create a struct MyStruct, and store a method variable called Function inside it pointing to MyFunction(). Finally, we run the tests.

is_struct() works fine when pointed directly at MyFunction.

However, if it's pointed at MyStruct.Function (which is a method variable and shouldn't register as a struct), it returns true.

Finally, to make absolutely sure there's not some weirdness going on with the fact we are referencing a struct to get to Function, we get all the variable names from inside the struct and pull them out one by one (or simply one in this case), then get the contents of those variables using variable_struct_get(), storing them in _value and then running the conditionals on that variable. In this case, both c AND d end up being true.

So at the end of all those tests, the results are:
A is 0, B is 1, C is 1, D is 1
So the Function inside MyStruct is registering as both a struct and method variable. I doubt that's intended behaviour and it basically breaks is_struct() when used to see if something is a struct or a method in all but the most naive cases.
 
Last edited:

chamaeleon

Member
Could not replicate...? I'm not using any beta releases, btw, in case that makes a difference
GML:
function MyFunction() {
    some_var = 0;
}

MyStruct = {
    Function : method(self,MyFunction)
}

// This works fine, a is equal to false
var a = is_struct(MyFunction);

// This line is the simplest version of the problem, b equals true here
var b = is_struct(MyStruct.Function);

show_debug_message(a);
show_debug_message(b);
Code:
0
0
Using your full code
Code:
A is 0, B is 0, C is 0, D is 1
 

Roldy

Member
Could not replicate...? I'm not using any beta releases, btw, in case that makes a difference
GML:
function MyFunction() {
    some_var = 0;
}

MyStruct = {
    Function : method(self,MyFunction)
}

// This works fine, a is equal to false
var a = is_struct(MyFunction);

// This line is the simplest version of the problem, b equals true here
var b = is_struct(MyStruct.Function);

show_debug_message(a);
show_debug_message(b);
Code:
0
0
Using your full code
Code:
A is 0, B is 0, C is 0, D is 1
Agreed.. Could not replicate.. Both return false.

Current IDE and Runtime on windows runner.

@RefresherTowel my output with your code is:

A is 0, B is 0, C is 0, D is 1
 
Could not replicate...? I'm not using any beta releases, btw, in case that makes a difference
GML:
function MyFunction() {
    some_var = 0;
}

MyStruct = {
    Function : method(self,MyFunction)
}

// This works fine, a is equal to false
var a = is_struct(MyFunction);

// This line is the simplest version of the problem, b equals true here
var b = is_struct(MyStruct.Function);

show_debug_message(a);
show_debug_message(b);
Code:
0
0
Using your full code
Code:
A is 0, B is 0, C is 0, D is 1
Ah, I should've pointed out, I'm on latest beta (306) and the problem didn't happen previous to beta 300, I believe.
 

8BitWarrior

Member
I believe I saw Russell talking about changes to is_struct() reporting methods as structs, amongst other things.
This is because methods are technically structs. MyFunction is a REAL value though. If you change its defintion to:
MyFunction = function() {}
It should then also return true as a struct.
 
I believe I saw Russell talking about changes to is_struct() reporting methods as structs, amongst other things.
This is because methods are technically structs. MyFunction is a REAL value though. If you change its defintion to:
MyFunction = function() {}
It should then also return true as a struct.
Nah, MyFunction = function() {} actually breaks it more. a, b, c and d all return true using that use case (originally when I ran into the problem it was with the setup you are describing, along the way bug-testing I changed it to function MyFunction() {}). So even the initial is_struct() call (involving the a variable) which was correctly returning false ends up returning true.
Scratch all that, misread what you said.
 
Last edited:
Well that sucks. If you have a struct that contains functions, for instance, a character stat struct with functions for getters and setters, etc, then deep copying is a pain in the arse without being able to distinguish between structs and methods. But also, this is a much more recent change than that post. It's not even live and I think two betas previously is when it was introduced.
 

Roldy

Member
Well that sucks. If you have a struct that contains functions, for instance, a character stat struct with functions for getters and setters, etc, then deep copying is a pain in the arse without being able to distinguish between structs and methods. But also, this is a much more recent change than that post. It's not even live and I think two betas previously is when it was introduced.

I agree that methods returning true for is_struct is not intuitive. However, as long as is_method returns true for methods and false for structs then everything remains distinguishable.
 
I agree that methods returning true for is_struct is not intuitive. However, as long as is_method returns true for methods and false for structs then everything remains distinguishable.
Yeah, it would be nice if that was how it worked, but BOTH is_struct() and is_method() returns true in my original example (local variables c and d are checking those two functions and they both return true).
 

Roldy

Member
Yeah, it would be nice if that was how it worked, but BOTH is_struct() and is_method() returns true in my original example (local variables c and d are checking those two functions and they both return true).
That is fine. That means you can distinguish them, as long as is_method return true for methods and false for structs... your example is testing a method which you have determine will return true for both.

so...

GML:
isAStruct = is_struct(_a) && !is_method(_a); // Will be true if _a is a struct and not a method

isAMethod = is_method(_a);  // Will be true if _a is a method and not a struct. Will return false if _a is a struct.

// Or more verbose

isAMethod = is_struct(_a) && is_method(_a); // Will be true if _a is a method and not a struct
Again, I agree that is_struct returning true for methods is confusing.. But they are distinguishable as long as is_method works. Essentially is_struct is ambiguous unless used in conjunction with is_method.

If this behavior is intentional then 'is_struct' should be renamed 'is_struct_or_method.' I am hoping it is just a bug.. because it is silly to have it work that way.
 
Last edited:
That is fine. That means you can distinguish them, as long as is_method return true for methods and false for structs... your example is testing a method which you have determine will return true for both.

so...

GML:
isAStruct = is_struct(_a) && !is_method(_a); // Will be true if _a is a struct and not a method

isAMethod = is_method(_a);  // Will be true if _a is a method and not a struct. Will return false if _a is a struct.

// Or more verbose

isAMethod = is_struct(_a) && is_method(_a); // Will be true if _a is a method and not a struct
Again, I agree that is_struct returning true for methods is confusing.. But they are distinguishable as long as is_method works. Essentially is_struct is ambiguous useless unless used in conjunction with is_method.

If this behavior is intentional then 'is_struct' should be renamed 'is_struct_or_method.' I am hoping it is just a bug.. because it is silly to have it work that way.
Ah, I see what you mean. Yeah, it certainly is counter-intuitive the way they've laid it out, but as long as there is some form of a definite check to distinguish between the two then at least it's useable, if not good.
 

chamaeleon

Member
@RefresherTowel Can you see what happens if you switch out is_struct() for typeof()? I'm curious if you get that it is a struct using this function as well.
GML:
function MyFunction() {
    some_var = 0;
}

MyStruct = {
    Function : method(self,MyFunction)
}

// This works fine, a is equal to false
var a = typeof(MyFunction);

// This line is the simplest version of the problem, b equals true here
var b = typeof(MyStruct.Function);

/* These lines below are the smallest "production" version of what I'm doing, pulling all the stuff out of a struct and checking to see
what each thing is, in this case both is_struct() AND is_method() will return true (i.e. c and d both equal true) */
var _names = variable_struct_get_names(MyStruct);
var _i = 0;
var c = 0;
var d = 0;
var _source = MyStruct;
repeat(array_length(_names))
{
    var _name = _names[_i];
    var _value = variable_struct_get(_source, _name);
    if (typeof(_value) == "struct") {
        c = true;
    }
    if (typeof(_value) == "method") {
        d = true;
    }
}
show_debug_message("A is "+string(a)+", B is "+string(b)+", C is "+string(c)+", D is "+string(d));
For my non-beta, release version I get this. "A" is number as plain functions (not assigned to variables, etc.) getting script indices (see typeof() documentation).
Code:
A is number, B is method, C is 0, D is 1
 
Top