#How to call a constructor by name?

1 messages · Page 1 of 1 (latest)

tawny sail
#

Say, i only have the name of the class, I want to construct but i want to call the constructor of this now.

var classname = "HexField";

var hexinst = new ...??? ();

how can i call this constructor, if i only have the name? do i need something like a function

function HexField_construct() {
  return new HexField();
}

like this?
or is there a better/smarter way?

heady tree
#

you need to resolve the name to a function and then new func();

#
/// @arg {String} nameString name of the script
/// @return {Real|Undefined} script index or undefined
/// @desc lmao
function Resolve(nameString) {
    var ind = 100001; // start indexing at the first GML script, runtime functions start at 0.
    repeat (100001) {
        var scname = script_get_name(ind);
        if (scname == nameString) {
            return ind;
        }
        else if (string_char_at(scname, 1) == "<") {
            break; // "<unknown>" or "<undefined>", name cannot contain angle brackets.
        }
        ++ind;
    }
    return undefined;
}

function Thing(arg) constructor {
    dummy = arg;
}

var thing1 = new Thing(1);
var thing2 = new (Resolve("Thing"))(1);
#

less than zero: "<undefined>"
Runtime functions: 0 - 100000
GML scripts: 100001 - 500000
Extension functions: 500001 - infinity...

#

don't ask why

#

only russell knows

tawny sail
#

ok i see - ty

tawny sail
# heady tree only russell knows

well, at some point they decided to map all those things to numbers and assigned number ranges - not the most common, but also not the worst possible way of doing this.
i have worked with lots of systems in the past, where they used database sequences like that - anything below 10000 was an "internal" account, anything below 1000 even an "admin" account...
why they didn't just use flags in the user table to mark an admin or internal... nobody will ever know

tawny sail
#

my approach (before knowing about scanning function names) would be to "register" constructables in some subsystem, like

register_constructor("HexField", function(args) { return new HexField(args); });

// ...where register_constructor could look like
function register_constructor(name, constr) {
  global.constructors[$ name] = constr;
}

...and when i need an instance, i'd call something like...

var myHexField = construct("HexField");

// ...where the "construct" function could look like
function construct(name, args = undefined) {
  return global.constructors[$ name](args);
}
heady tree
#

uhh

#

script inside the new expression doesn't have to be runtime only

#

var a = Thing; new a(); works

#

var a = Thing + 1; new a(); also works (but undefined behavior)

left stone
#

you don't need that funky thing nik sent, because no built-in functions are going to be constructable

#

you could just use asset_get_index("HexField")

#

I believe

#

so all together that would be:

var classname = "HexField";
var hexcons = asset_get_index(classname);

var hexinst = new hexcons();```
tawny sail
#

Oh yea - this looks easy enough to be maintainable (means, in a year or two i still understand what i did here 😜 )

But: There is no possible check, whether this is really a constructor function, right? so it will crash if something wrong is set to "classname" --- that's perfectly ok, because it would be a coding mistake then, it may crash -- just wanted to point that out

severe flax
#

(Also realised this post is a lil old oops)

tawny sail
#

thanks -- i implemented it in the meantime and my savegame system now even calls constructors when loading the game. all a saveable class has to do, is to "register" it with the savegame so it knows, that there's a constructor for this class and then it calls it when loading