Skip to content

Dynamic Inheritance fun with IQuackFu

rollynoel edited this page Jun 12, 2013 · 3 revisions

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

Clone this wiki locally