Dynamic Object
This simple application demonstrates DynamicObject from Project Galahad.
I'm currently working on improving the hinting mechanism and record marshalling, and this demo is helping to drive those changes.
DynamicObject is named after the C# type which uses the DLR for late binding. Similarly, the TDynamic type is used to activate runtime dispatch.
I like Ruby's method_missing approach, so MethodMissing was introduced.
Apart from the general benefits of dynamic interception in a static language, the real value in this approach is that it enables the creation of DSLs.
The Demo
To make the demo a bit more fun, I used a traffic light example.
On the form, I have a combo box with these items:
- Red
- Amber
- Green
- Dynamo!
When the user selects an item, the text is dispatched at runtime to a controller object. If the text matches a real method name, that method is invoked. If it doesn't exist, the call falls through to MethodMissing.
The Dynamic Controller
Here's the controller class, which inherits from TDynamicObject:
TTrafficController = class(TDynamicObject)
private
fLights: ITrafficLights;
public
// handlers for the text: Red, Amber, Green
procedure Red;
procedure Amber;
procedure Green;
// catches unknown method calls, like Ruby's method_missing
function MethodMissing(const aName: string; ...): Variant; override;
procedure Use(const aLights: ITrafficLights);
end;
And the implementation of MethodMissing:
function TTrafficController.MethodMissing(const aName: string; ...): Variant;
begin
fLights.Malfunction;
end;
Dispatching from the UI
The main form code is straightforward:
procedure TMainForm.cboColorsSelect(Sender: TObject);
begin
var color := cboColors.Text;
// dispatch the text to our class.
TDynamicHelper.Invoke(fController, color, []);
end;
In this example we are dispatching text directly to the object.
That means:
- selecting Red calls fController.Red
- selecting Amber calls fController.Amber
- selecting Green calls fController.Green
- selecting Dynamo! calls MethodMissing
This is a different dispatch approach to the Xml demonstration, but the same underlying mechanism:
var car := TXml.New('car');
car.year := 2022;
car.reg := 'AB12 CDE';
car.specs['make'] := 'Toyota';
car.specs['model'] := 'Corolla';
var xml := car.AsPrettyXml;
The Demo
The dynamic support used in this demo comes from Base.Dynamic.pas, pulled in from the Project Galahad library along with a few dependencies.
The demo-specific code is in Forms.Main.pas and Utils.TrafficController.pas, and a few frames.
The source code is available here.