A delegate is a helper object used by another object. The delegator may send the delegate certain messages, and provide a default implementation when there is no delegate or the delegate does not respond to a message. This pattern is heavily used in Cocoa framework on Mac OS X. See also wp:Delegation pattern.

Objects responsibilities:

Delegator:

 Keep an optional delegate instance.
 Implement "operation" method, returning the delegate "thing" if the delegate respond to "thing", or the string "default implementation".
Delegate:

 Implement "thing" and return the string "delegate implementation"
Show how objects are created and used. First, without a delegate, then with a delegate that does not implement "thing", and last with a delegate that implements "thing".

 
Module Checkit {
	\\ there are some kinds of objects in M2000, one of them is the Group, the user object
	\\ the delegate is a pointer to group
	\\ 1. We pass parameters to function operations$(), $ means that this function return string value
	\\ 2. We see how this can be done with pointers to group
	global doc$  \\ first define a global (for this module) to log output
	document doc$="Output:"+{
	}
	class Delegator {
	private:
		group delegate
		group null
	public:
		function operation$ {
			if not .delegate is .null then
				try ok {
					ret$="Delegate implementation:"+.delegate=>operation$(![])
					\\ [] is the stack of values (leave empty stack), ! used to place this to callee stack
				}
				if not ok or error then ret$="No implementation"
			else
				ret$= "Default implementation"
			end if
			\\ a global  variable and all group members except arrays use <= not =. Simple = used for declaring local variables
			doc$<=ret$+{
			}
			=ret$
		}	
	class:
		Module Delegator {
				class none {}
				.null->none()
				If match("G") then .delegate->(group) else .delegate<=.null
		}
	}
 
	Class Thing {
		function operation$(a,b) {
			=str$(a*b)
		}	
	}
	Module CallbyReference (&z as group) {
		Print Z.operation$(5,30)
	}
	Module CallbyValue (z as group) {
		Print Z.operation$(2,30)
	}
	Module CallbyReference2 (&z as pointer) {
		Print Z=>operation$(5,30)
	}
	Module CallbyValue2 (z as pointer) {
		Print Z=>operation$(2,30)
	}
	\\ Normal Group  ' no logging to doc$
	N=Thing()
	Print N.operation$(10,20)
	CallbyReference &N
	CallbyValue N
	N1->N    ' N1 is a pointer to a named group
	Print N1=>operation$(10,20)
	CallbyReference2 &N1
	CallbyValue2 N1
	N1->(N)  ' N1 now is a pointer to a float group (a copy of N)
 	Print N1=>operation$(10,20)
	CallbyReference2 &N1
	CallbyValue2 N1
	\\ using named groups (A is a group, erased when this module exit)
	A=Delegator()
	B=Delegator(Thing())
	Print A.operation$(10,20)
	Print B.operation$(10,20)
	A=B
	CallbyReference &A
	CallbyValue A
	\\ M2000 has two kinds of pointers to groups
	\\ one is a pointer to a no named group (a float group)
	\\ a float group leave until no pointer refer to it
	\\ using pointers to groups (A1 is a pointer to Group)
	A1->Delegator()
	B1->Delegator(Thing())
	Print A1=>operation$(10,20)
	Print B1=>operation$(10,20)
	A1=B1
	CallbyReference2 &A1
	CallbyValue2 A1
	\\ Second type is a pointer to a named group
	\\ the pointer hold a weak reference to named group
	\\ so a returned pointer of thid kind can be invalid if actual reference not exist
	A=Delegator() ' copy a float group to A
	A1->A
	B1->B
	Print A1=>operation$(10,20)
	Print B1=>operation$(10,20)
	A1=B1
	CallbyReference2 &A1
	CallbyValue2 A1
	Group Something {		
	}
	B=Delegator(Something)
	Print B.operation$(10,20)
	CallbyReference &B
	CallbyValue B
	Report Doc$
	Clipboard Doc$
}
Checkit
 
 