Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

constructor_call #99

Open
tabularelf opened this issue Dec 1, 2024 · 7 comments
Open

constructor_call #99

tabularelf opened this issue Dec 1, 2024 · 7 comments
Labels
feature ✨ For feature requests and implementations

Comments

@tabularelf
Copy link

tabularelf commented Dec 1, 2024

Note: I have wanted to submit a function like this for a long while into the community toolbox, but I wanted to wait until things were relatively stable. As of 2024.11, script_execute_ext is now being supported to allow treating the current scope as an instance of a constructor function! See YoYoGames/GameMaker-Bugs#7995 for more info.

What does it do?

constructor_call(constructor, args, [length], [offset]) at its simpliest form, mimics the behaviour of script_execute_ext, but rather than treating it like a normal function, it runs as if you were to do new Construct(arg, ...). This allows you to create essentially a constructor instance with as many arguments as needed.

Useful for scenarios such as:

  • Deserializing complex data (especially important for constructor instances that are needing to be saved/loaded)
  • Adding in support for declaring a new instance of a constructor from a varying level of arguments, in a code interpreter.
  • Passing in an array of arguments to a constructor function, making it universally compatiable with any constructor function. (Including libraries), and allowing to pass in an unlimited amount of arguments, without knowing the exact number of arguments a constructor function requires.
  • Avoiding a pyramid of doom-styled constructor_call implementation.

Can you give us an example of how it can be used?

// Some library
function Vector3(_x, _y, _z) constructor {
    x = _x;
    y = _y;
    z = _z;

   // Static methods appear below here, but for demonstration purposes lets assume I wrote them
}


// ==Normal way==
// obj_player
pos = new Vector3(0, 32, 0);

// ==constructor_call way==
// Default init script
global.vec3_pos_default = [0, 32, 0];

// obj_player
pos = constructor_call(Vector3, global.vec3_pos_default);

Why should the community toolbox have this?

This has been a long requested feature, dating back to late July of last year. Specifically YoYoGames/GameMaker-Bugs#3055. As this has it's multiple use cases, I feel that it warrents some benefits in being apart of the community toolbox.

What does the function code look like?

I have written a gist awhile ago when I had confirmation that the changes for 2024.11 will be included (and after some bug reports for VM/YYC)
https://gist.github.com/tabularelf/d686a940f46c7c45daa2dd78b0358d30

@tabularelf tabularelf changed the title constructor_call(constructor, args, [length], [offset]) constructor_call Dec 1, 2024
@Alphish Alphish added the feature ✨ For feature requests and implementations label Dec 13, 2024
@tinkerer-red
Copy link

Made constructor_call and constructor_call_ext in the time being making use of 2024.11's update to both script_execute to allow for calling constructors.
https://gist.github.com/tinkerer-red/9ed172f0db46df862f0b667b9d27da72

@tabularelf
Copy link
Author

tabularelf commented Jan 28, 2025

Made constructor_call and constructor_call_ext in the time being making use of 2024.11's update to both script_execute to allow for calling constructors. https://gist.github.com/tinkerer-red/9ed172f0db46df862f0b667b9d27da72

This is nothing more than just replacing new MyConstructor() with constructor_call(MyConstructor, arg1, arg2, arg3), which I feel misses the whole point of constructor_call. (Yes, I know you have constructor_call_ext, but that still is riddled with issues).

@Alphish Alphish added this to the 24.11.0 Release milestone Jan 28, 2025
@tinkerer-red
Copy link

Oh my apologies, when viewing your initial post I must have missed the gist link on the bottom. It did not occur to me there was already a suggestion. Though I do believe sticking to the standards of gml syntax *_ext would be the array variant. Specifically using constructor_call over the new *() system would more-so be for consistency sake to include, not that it's entirely viable as of currently. I believe including both future proofs the code significantly, even if currently unneeded. Additionally if desired an argument for binding the static variables would be optional here in which case having the two functions separated would be ideal.

@Alphish
Copy link
Owner

Alphish commented Jan 31, 2025

constructor_call should be seen as a counterpart to method_call, which is also array based.

This contrasts with script_execute and script_execute_ext, but script_execute itself comes from pre-modern GML when we couldn't do "function_variable(arg1, arg2, arg3)" syntax.

So yeah, I'd rather go for a single array-based constructor_call here.

@tabularelf
Copy link
Author

tabularelf commented Jan 31, 2025

I figured I should add to that, and on top.

  • *_ext isn't universal. There is no method_call_ext variant for method_call. method_call is the method equivilant of script_execute_ext.
  • Going with that above, there is nothing to future proof really here because you can just call a method function without having an intermediate function in place. (Like pre-modern GML kind of required you to do any time you wanted to reference a function). Same goes for built in functions. Same goes for GML user defined functions. The benefits these days are pretty much "speed benefits", going off by the script_execute changes that were made awhile ago.
  • Statics isn't really necessary here I've found. In fact, previously I did have it with my implementation "just in case", but it turns out from my own testing that it wasn't necessary at all. Perhaps there is something that I'm missing, but as far as I'm concerned, the struct is treated exactly as if it's an instance of that constructor. So adding in an option for static variables binding doesn't really make sense, given that it's done for us anyway. Whether we want it or not. (And personally if you didn't want static variables to bind, just don't use static variables in the first place??)

@tinkerer-red
Copy link

tinkerer-red commented Feb 1, 2025

there is nothing to future proof really here because you can just call a method function without having an intermediate function in place

In the event they make use of string acceptance, similar to the asset or string argument input for asset_get_index and asset_get_type (which relayed a recent bug on differences between windows compiles and GX compiles as found here). Though I dont see this being a practical addition it doesnt mean it isnt a possible addition one day for script_execute to accept strings in the future.

Though the argument for method_call does make this more understandable as to why this would only be a single function instead of an extended variant. I dont have a strong enough opinion for insisting an extended variant though, simply a devils' advocate to consider both sides.

Also I had no idea statics were carried into an arbitrary struct when executing a constructor function on it. possibly a unintended feature or bug? the syntax doesnt appear to imply that it will write any statics to the object, raises even further questions as to what happens to an object executing a constructor. But when building out a ECS or any system which inherits from more then one parent the static binding would be a good option. (if possible that is)

@tabularelf
Copy link
Author

tabularelf commented Feb 4, 2025

Also I had no idea statics were carried into an arbitrary struct when executing a constructor function on it. possibly a unintended feature or bug?

It's a feature, the whole intent is to treat it exactly as if we had called new MyConstructor(), so it's fair to say it's appropriate to do that.

In the event they make use of string acceptance, similar to the asset or string argument input for asset_get_index and asset_get_type (which relayed a recent bug on differences between windows compiles and GX compiles as found YoYoGames/GameMaker-Bugs#8128). Though I dont see this being a practical addition it doesnt mean it isnt a possible addition one day for script_execute to accept strings in the future.

I don't think YoYoGames wants to start adding a string -> ref interpreter into various of functions, let alone script_execute/script_execute_ext...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature ✨ For feature requests and implementations
Projects
None yet
Development

No branches or pull requests

3 participants