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

Extended struct functionalities #14

Open
Gizmo199 opened this issue Jun 17, 2023 · 2 comments
Open

Extended struct functionalities #14

Gizmo199 opened this issue Jun 17, 2023 · 2 comments
Labels
feature ✨ For feature requests and implementations

Comments

@Gizmo199
Copy link

Gizmo199 commented Jun 17, 2023

These are some various extended struct functions I use quite often.

/// @func struct_merge(source, dest)
/// @arg source
/// @arg dest
/// @desc adds or overwrites the destination struct key/values pairs from the source struct
/// @returns {struct}
function struct_merge(_source, _dest){
	struct_foreach(_source, method({dest : _dest}, function(_name, _value){
		dest[$ _name] = _value;
	}));
	return _dest;
}

/// @func struct_copy(struct)
/// @arg struct
/// @desc returns a copy of the struct you supply
/// @returns {struct}
function struct_copy(_struct){
	return struct_merge(_struct, {});
}

/// @func struct_create(constructor, variable_struct)
/// @arg constructor
/// @arg var_struct
/// @desc returns a new or existing constructor with with variables to assign to the new struct
/// @returns struct
function struct_create(_constructor, _var_struct={}){
	if ( is_struct(_constructor) ) return struct_merge(_var_struct, _constructor);
	return struct_merge(_var_struct, new _constructor());
}

/// @func struct_create_ext(constructor, call_func_on_create, variable_struct)
/// @arg constructor
/// @arg call_func_on_create
/// @arg var_struct
/// @desc returns a new or existing constructor with with variables to assign to the new struct and allows you to call a function within the struct or variable struct when created
/// @returns struct
function struct_create_ext(_constructor, _callfunc="", _var_struct={}){
	var _new_struct = struct_create(_constructor, _var_struct);
	if ( _callfunc != "" && _new_struct[$ _callfunc] != undefined ) _new_struct[$ _callfunc]();
	return _new_struct;
}

Example:

function Test() constructor {
	name = "constructor";	
}
function Test2() constructor {
	name = "constructor 2";	
	func = function(){
		show_debug_message(name);	
	}
}

var test, test2;
test = struct_create(Test, {name : "Gizmo"});
test2= struct_create(struct_copy(test), struct_create(Test2, {name : "199"}));

show_debug_message(test.name);
test2.func()
@Alphish
Copy link
Owner

Alphish commented Jun 17, 2023

Regarding struct_merge - I would often use a similar function struct_assign, working the same as JavaScript's Object.assign function.

One important difference compared to your implementation was that the destination struct was the first argument, and then one or more source structs would follow. In case of overlapping properties, the later source overwrites properties from the earlier sources.

Regarding struct_copy - with GameMaker 2023.4 (which is the one I plan to support for now), it should be possible to do variable_clone(_struct, 1); as a native function, it might have potential to be even faster. Myself, I was considering something like struct_clone_shallow and struct_clone_deep, though especially for the latter I would need to figure out how variable_clone handles struct's constructor type and methods (which themselves are special kinds of structs). My implementation of struct cloning assumed that self-bound methods were re-bound to the clone, while other-bound methods were copied as-is.

struct_create and struct_create_ext are a bit too specific to me, in that a generic name like struct_create can be interpreted in very different ways. Here it means creating a struct of a given constructor and some initial values, but one could imagine other struct_create which allows passing alternating keys and values, for example.

Personally, the scenarios where I would want to set some extra values after constructing (rather than passing them as constructor parameters to begin with) are so few and far inbetween that I'd be fine with occasional call like struct_assign(new Foo(), { bar: 2, baz: 3 }) instead.

Heck, if someone has the kind of constructor they want to pass some extra struct of initial values to, they might just use struct_assign inside contructor and then run the initialisation logic:

function HighlyConfigurableStruct(_config) constructor {
    struct_assign(self, _config);
    init();

    static init = function() { ... }
}

@Alphish Alphish added the feature ✨ For feature requests and implementations label Jun 18, 2023
@Gizmo199
Copy link
Author

That sounds good too. This is just how i've used them since I use a lot of 'generic' structs (for things like items, weapons, etc). I tend to use structs a lot like objects a lot of the time for non-drawing purposes. I like struct_assign too. :)

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

2 participants