Demonstrate how to dynamically add variables to an object (a class instance) at runtime.

This is useful when the methods/variables of an instance are based on a data file that isn't available until runtime. Hal Fulton gives an example of creating an OO CSV parser at An Exercise in Metaprogramming with Ruby. This is referred to as "monkeypatching" by Pythonistas and some others.

 
import morfa.base;
 
template <T>
public struct Dynamic
{
    var data: Dict<text, T>;
}
 
// convenience to create new Dynamic instances
template <T>
public property dynamic(): Dynamic<T>
{
    return Dynamic<T>(new Dict<text,T>());
}
 
// introduce replacement operator for . - a quoting ` operator
public operator ` { kind = infix, precedence = max, associativity = left, quoting = right }
template <T>
public func `(d: Dynamic<T>, name: text): DynamicElementAccess<T>
{
    return DynamicElementAccess<T>(d, name);
}
 
// to allow implicit cast from the wrapped instance of T (on access)
template <T>
public func convert(dea: DynamicElementAccess<T>): T
{
    return dea.holder.data[dea.name];
}
 
// cannot overload assignment - introduce special assignment operator
public operator <- { kind = infix, precedence = assign }
template <T>
public func <-(access: DynamicElementAccess<T>, newEl: T): void
{
    access.holder.data[access.name] = newEl;
}
 
func main(): void
{
    var test = dynamic<int>;
 
    test`a <- 10;
    test`b <- 20;
    test`a <- 30;
 
    println(test`a, test`b);
}
 
// private helper structure
template <T>
struct DynamicElementAccess
{
    var holder: Dynamic<T>;
    var name: text;
 
    import morfa.io.format.Formatter;
    public func format(formatt: text, formatter: Formatter): text
    {
        return getFormatFunction(holder.data[name])(formatt, formatter);
    }
}
 