Defining instance variables with class method after compilation?

Is there a way to encapsulate a variable within a class instance dynamically? I.e. setting it up with a string as argument for the variable name and then being able to access that variable with an instance method like:

a=MyClass("varName");

a.varName;

I want to be able to put an arbitrary number of variables with arbitrary names into the class through arguments when creating an instance but after hours of browsing the docs I’m starting to believe that instance variables needs be defined at compilation by nature. Am I right in this suspicion?

A somewhat different, albeit related question:
As a workaround I’ve have had some luck with instantiating environment variables through:

	makeAgens_ {arg argSynthDef;
	    // Get argument names from supplied SynthDef
        var controls = SynthDescLib.global.synthDescs.at(argSynthDef).controls;
		synthDef = argSynthDef;
        
        //Create an event to put Agens into.
		"~% = ()".format(synthDef).interpret;

        //Put Agens with corresponding key into event.
		controls.do{|control|	
        var name = control.name;
			"~%.put(%%, Agen(9));".format(synthDef, "\\", name).interpret;
		};
	}

// Agen is just a class I've been working on.
// The above method is a way to generate a bunch of them at once.

Is this way of expressing notions with strings and interpreting those strings an acceptable way of doing things? I feel like it’s an ugly fix in some way.

There is no facility of any kind to add variables dynamically. All variables must be defined at compile time.

The Library class is a global repository where data can be stored at any time.

So you could do Library.put(MyClass, \varName, value) to set, and Library.at(MyClass, \varName) to get.

Also don’t use strings for the name – symbols are better for this.

hjh

There are ways to fake this kind of behavior, but I’d recommend being careful with them and thinking hard about whether you absolutely need to do things this way.

One example of how you might do something that looks from the outside like adding variables dynamically would be to give your Class an internal dictionary and override doesNotUnderstand to dispatch to this dictionary:

MyClass {
    var dict;

    *new { ^super.new.init }

    init { dict = IdentityDictionary.new }

    add {|association| dict.add(association) }

    doesNotUnderstand {|selector|
        dict[selector].notNil.if({ ^dict[selector] }, { super.doesNotUnderstand(selector) })
    }
}

In use:

~instance = MyClass.new

~instance.add(\foo -> \bar) // add an association

~instance.foo // should return \bar

~instance.baz // should throw a DoesNotUnderstandError

yes, there actually is. (well, methods not variables but they’ll function the same)

MyClass {
	*new {|a|
		^super.new.addUniqueMethod(a, {400+400});
	}
}

a=MyClass(\varName);
a.varName;  //-> 800

a.addUniqueMethod(\var2, {222})
a.var2  //-> 222

you can find this technique used here and there in for example wslib quark.

but watch out, whenever you feel the need to generate any type of variable or method name automatically, that is usually a sign of that you have a troublesome class design to begin with. likely there’s a better and simpler way.