Boo's IQuackFu interface enables adding behavior to a class at runtime. This example
shows how to add dynamic inheritance to boo, also called mixin programming or delegation |
The following Mixup class can be used to add new class behavior to an object at runtime. First, the code for Mixup:
// Bill Wood, Nov 2004
import System.Reflection
class Mixup (IQuackFu):
static defaultBF = BindingFlags.Instance | BindingFlags.Static |\
BindingFlags.Public | BindingFlags.FlattenHierarchy
static invokeBF = defaultBF | BindingFlags.InvokeMethod
static getPropertyBF = defaultBF | BindingFlags.GetProperty | BindingFlags.GetField
static setPropertyBF = defaultBF | BindingFlags.SetProperty | BindingFlags.SetField
private methods = {}
private properties = {}
def QuackInvoke(name as string, args as (object)) as object:
o = methods[name]
if o is null:
raise System.InvalidOperationException("Method ${name} not found in class ${self.GetType()}")
return o.GetType().InvokeMember(name, invokeBF, null, o, args)
def QuackGet(name as string, params as (object)) as object:
o = properties[name]
if o is null:
raise System.InvalidOperationException("Member ${name} not found in class ${self.GetType()}")
return o.GetType().InvokeMember(name, getPropertyBF, null, o, null)
def QuackSet(name as string, params as (object), value as object) as object:
o = properties[name]
if o is null:
raise System.InvalidOperationException("Member ${name} not found in class ${self.GetType()}")
return o.GetType().InvokeMember(name, setPropertyBF, null, o, (value,))
def mixup(o as object):
t = o.GetType()
for m in t.GetMethods(invokeBF):
if methods[m.Name] is null:
methods[m.Name] = o
for m in t.GetProperties(getPropertyBF):
if properties[m.Name] is null:
properties[m.Name] = o
for m in t.GetFields(getPropertyBF):
if properties[m.Name] is null:
properties[m.Name] = o
return o
def unmixup(o as object):
helper = def (hash as Hash):
d = []
for m in hash:
if m.Value is o:
d.Add(m.Key)
for s in d:
hash.Remove(s)
helper(methods)
helper(properties)
return o
def constructor():
mixup(self)
|
Mixup can be instantiated directly:
class Test:
def say(s):
print(s)
z as duck = Mixup() // z is a mixed up class!
l = z.mixup(List()) // add a List() to z
z.mixup(Test()) // add a Test() to z
z.Push("hi from x") // Push using List.Push
z.say("${z.Count}, ${z.Pop()}, ${z.Count}") // Output: 1, hi from z, 0
print z isa List // not REALLY a list, just has List behavior
z.unmixup(l) // remove List behavior
z.Push("hi") // System.NullReferenceException: Method Push not found in class Mixup
|
Or, it can be subclassed:
class X(Mixup): // X subclasses Mixup
private _list = []
def constructor():
mixup(_list) // add list behavior to X
for i in range(10):
_list.Add(i) // initialize _list
x as duck = X()
x.Push("hi from x")
print x.Pop(), x.Pop(), x.Pop() // hi from x 9 8
|