Search code examples
delphimonkeypatchingdwscript

DWScript, Monkey Patching: Add method or property at runtime


At the moment I wrote a ORM mapping for DWScript + SQLite. I have successfully implemented mapping for normal properties (like string or integer), but now I want to add Foreign Keys and Many To Many relations. For this I have planed, to declare the Foreign Key property in class A and then add a relationmanager to class B at runtime, to model the relation. I know I could place the relationmanager in class B in sourcecode, but imagine if I had some models in my application that have Foreign Keys to the user model, declared in the framework. It wouldn't practical to modify the framework for every new application.

My Question: How can I add a new property, field or function to a object/class at script runtime?

Here some code for explaining:

type TClassB = class;

type TRelationManager = class end; // a class which controls the access to the relation, only a stub

type  
  [XORM_ForeignKey('LinkB')] //attribute to indicate property "LinkB" as Foreign Key
  TClassA = class(TBaseModel)
    private
      FLinkB : TClassB;
    published
      property LinkB : TClassB; //Foreign Key to TClassB
  end;

  TClassB = class(TBaseModel)
    private
    published
        // This field should be added at runtime and not directly in the source code, as shown here.
        RelationManager : TRelationManager; 
  end;

Solution

  • DWS contributor here. DWS doesn't support "monkey patching;" the script source is as static as Delphi source files. From the outside of the script (in native code-land) things are different, and it's possible to modify the objects that represent a class, but this isn't recommended since all of the offsets are already calculated at compile time, so you could end up causing serious bugs.

    If you're looking for AOP, though, what you want is to hook into the compile-time process and insert things at that point, before compilation is finalized. But even then, unless there's already code referring to the field you're inserting, having this new field won't do much good. I'm not sure exactly what you're trying to accomplish, unless you plan on using DWS's RTTI to connect to the field manager...