Saturday, May 14, 2011

Going beyond dependency injection with MEF for Delphi

You probably read Nicks recent posts about his experiences with the Delphi Spring Framework and especially with their DI Container. To be honest I actually don't know how far they go with it but Nick most likely will enlighten us soon.

As you may know I really like many concepts that we can find in .Net and here is another one: the Managed Extensibility Framework. Its core parts are basically a DI container and one catalog (or more) that contains information about exports and imports. So you can create classes that are not referenced directly by any other part of your application and define an export on them. But that alone would be useless because we actually want to use that class, don't we? So on the other side you can specify an import. Be it for the constructor of another class or its properties.

In the following I will show you how to use this concept in your Delphi application. Because I am very bad in finding examples I took a look around and found this nice example for MEF and I will use very similar examples.

Hello world

So, let's get started. We will create a console application that looks like this:
program MEFSample;

{$APPTYPE CONSOLE}

uses
  MEFSample.Main,
  MEFSample.Message,
  System.ComponentModel.Composition.Catalog,
  System.ComponentModel.Composition.Container,
  SysUtils;

var
  main: TMain;
  catalog: TRttiCatalog;
  container: TCompositionContainer;
begin
  ReportMemoryLeaksOnShutdown := True;
  main := TMain.Create;
  catalog := TRttiCatalog.Create();
  container := TCompositionContainer.Create(catalog);
  try
    try
      container.SatisfyImportsOnce(main);
      main.Run();
    except
      on E: Exception do
        Writeln(E.ClassName, ': ', E.Message);
    end;
  finally
    container.Free();
    catalog.Free();
    main.Free;
  end;
  Readln;
end.


We create the catalog which pulls all the exports and imports from the RTTI and pass it to the composition container which is responsible for resolving those informations when creating new objects or using the SatisfyImportsOnce method on an already existing object like in our example.

Our MEFSample.Main unit looks as follows:
unit MEFSample.Main;

interface

uses
  System.ComponentModel.Composition;

type
  TMain = class
  private
    FMsg: TObject;
  public
    procedure Run;

    [Import('Message')]
    property Msg: TObject read FMsg write FMsg;
  end;

implementation

procedure TMain.Run;
begin
  Writeln(Msg.ToString);
end;

end.

The unit System.ComponentModel.Composition contains all the attributes. If you do not include it, you get the "W1025 Unsupported language feature: 'custom attribute'" compiler warning which means those attributes are not applied.
We specify the Msg property as named import. When calling the SatifyImportOnce Method (which is also used internally when creating objects with the CompositionContainer) it looks for all those imports and tries to find matching exports.

That leads us to the last unit for this first example:
unit MEFSample.Message;

interface

uses
  System.ComponentModel.Composition;

type
  [Export('Message')]
  TSimpleHello = class
  public
    function ToString: string; override;
  end;

implementation

function TSimpleHello.ToString: string;
begin
  Result := 'Hello world!';
end;

initialization
  TSimpleHello.ClassName;

end.

Again, we need to use System.ComponentModel.Composition to make the Export attribute work. We have some simple class that is exported with a name.
One important point: Since this class is referenced nowhere else in our application the compiler will just ignore it. That is why we need to call some method of it in the initialization part of the unit which is called when the application starts. So this makes the compiler include our class.

When we start the application we see the amazing "Hello world".

Using contracts

This worked but actually that is not how we should do this. So let's define a contract called IMessage.
unit MEFSample.Contracts;

interface

uses
  System.ComponentModel.Composition;

type
  [InheritedExport]
  IMessage = interface
    ['{7B32CB2C-F93F-4C59-8A19-89D6F86F36F1}']
    function ToString: string;
  end;

implementation

end.
We use another attribute here which tells the catalog to export all classes, that implement this interface. We also need to specify a guid for that interface. We change our TSimpleHello class:
TSimpleHello = class(TInterfacedObject, IMessage)
and in our main class we change the Msg property:
[Import]
property Msg: IMessage read FMsg write FMsg;

The more the better!

What keeps us from creating another class that implements IMessage? Nothing, so let's do this:

type
  TSimpleHola = class(TInterfacedObject, IMessage)
  public
    function ToString: string; override;
  end;

implementation

function TSimpleHola.ToString: string;
begin
  Result := 'Hola mundo';
end;

initialization
  TSimpleHola.ClassName;

When we run this we get an ECompositionException with message 'There are multiple exports but a single import was requested.' which totally makes sense. So we need to change something:
[ImportMany]
property Msgs: TArray<IMessage> read FMsgs write FMsgs;
and the Run method:
procedure TMain.Run;
var
  m: IMessage;
begin
  for m in FMsgs do
    Writeln(m.ToString);
end;

We start the application and get both messages.

Breaking it down

What if we only want to export and import smaller parts than a whole class? Well then define the export on those parts!

type
  TSimpleHello = class(TInterfacedObject, IMessage)
  private
    FText: string;
  public
    function ToString: string; override;
    [Import('Text')]
    property Text: string read FText write FText;
  end;

  TTextProvider = class
  private
    function GetText: string;
  public
    [Export('Text')]
    property Text: string read GetText;
  end;

implementation

function TSimpleHello.ToString: string;
begin
  Result := FText;
end;

function TTextProvider.GetText: string;
begin
  Result := 'Bonjour tout le monde';
end;

initialization
  TSimpleHello.ClassName;
  TTextProvider.ClassName;

So what is this all about? Different parts of the applications can be created and put together in a declarative way using attributes. With MEF you can create code that is free of unnecessary dependencies - clean code.

The sample and the required units can be downloaded here or directly from the svn. The source is based on some implementation I originally found here.

P.S. I just made the sample also work in Delphi 2010 - this is available in svn.

Monday, May 9, 2011

Lambdas and expression trees in Delphi

Ever wanted to write something like this in Delphi?

for cust in customers.Where(c => c.CustomerId = 'ALFKI') do ...

Actually in Delphi you have to write it like this.

for cust in customers.Where(
  function(c: TCustomer): Boolean
  begin
    Result := c.CustomerId = 'ALFKI';
  end) do ... 

Ugh, lots of code just to declare the anonymous method. Well, we are used to writing more letters in Delphi so that is not really the problem. Another thing is more interesting: expression trees. What can you do with it? Lots of cool stuff. The most interesting for me at least was the ability to create SQL statements with their help. Above for in loop generates adds a where clause to the select statement when using Linq to SQL in .Net. But Delphi does not have such expression trees for anonymous methods... Until now!

Since I have been working with delphi-coll the first time I was wondering if I can actually use them to create something similar to the ADO Entity Framework. The biggest problem was to translate for in loops like above to proper SQL that only fetched the wanted data from the database instead of doing client side filtering. After looking into how .Net does it was obvious to me. I need some kind of support for lambda expressions or more specific the possibility to create some expression tree that I can use to create my SQL statements. But how to inject some kind of expression into a function (in our case the where function) without writing an anonymous function or at least without writing a super complicated one that only works when using some SQL queryable?

When I googled "Delphi lambda linq" the second hit brought me to the first idea. Basically a combination of records with operator overloading containing interfaces. You can do some funny stuff with them but there is some limitation. As soon as you want to access a property of some object you are lost (like we want to do in our example). So how to make a property or function call without actually calling it. I know that sounds weird but what I want to achieve is to record the complete expression. This brings us to invokable custom variant types. I am not going to explain how they work but if you want to know more you can read some articles about it here and there.

The important thing is: We can have calls to a property or method like in our example (c.CustomerId) without actually calling and getting a return value. Well we get a return value but it will be a variant which encapsulates the expression object for this property or method. So we have the information now but can invoke it later. Let's look at our anonymous method we use for filtering our customer list. It gets one parameter of the type TCustomer and returns a boolean. So how to write our expression now?

for cust in customers.Where(
  TLambda.From<TCustomer, Boolean>(Arg1.Customer = 'ALFKI')) do ...

Oh wow, whats this TLambda and that Arg1?! TLambda is a record with some static methods like From which supports all kinds of TFunc defined in SysUtils (well not all so far but they will get added). This methods creates some anonymous method and returns it.
Arg1 is a function (there are 3 more) to create an expression that takes care of the first parameter of the anonymous method. So in our case the TCustomer object we pass in when we call the method.

So what about that expression tree? We actually can get that out of the method reference. Wait what? Yes, as we know they are just objects hidden behind some interface. Which means: you can get RTTI for them. And getting RTTI means you can extract information and even modify them. TLambda has 2 methods to get and set the expression that is executed inside the method when its called.

So now we can inspect and iterate our expression tree and generate where clauses and other funny things. So if you want to access a parameter of the method just use the ArgX functions. If you want to use variable capturing put them into Arg function so you can use the current value when actually executing the method (just supported for objects so far).
One thing you have to remember is: You cannot use normal functions inside that expression because that results in direct execution. But you can write wrappers for them as shown in one of the samples.

All in all this is a very early prototype but it works pretty well so far in a single threaded application.

To make this work in your program just use System.Lambda (and System.Expressions when you want to create your own expression tree).

You can also see how it works in the 2 new demos (Sample6 and Sample7). For the second sample you need delphi-coll to make it work.

Sunday, May 8, 2011

New features for data bindings

In the last week bindings got a lot new features:

Property path:
That means if you want to bind for example MainForm.Font.Size to your control you easily specify it by setting the MainForm as Source and Font.Size as SourcePropertyName.
You could do that before already but you had to bind to MainForm.Font as Source and Size as SourcePropertyName. But that was not possible in the IDE because of the limitation of the property editor for the source property. It is on the todo list to support nested object properties for the source property in the IDE also.

Collections:
Bindings now support collections. More exactly, descendants of TEnumerable<TObject> that implement INotifyCollectionChanged. There is a new base class called TObservableCollection<T> which inherits from TObjectList<T>. I added one control so far that supports this: TListBox.
There is a new sample that shows how to display a list of data objects in the listbox and how to bind other controls to edit the selected item.
Since that feature is still under development you might notice some problems with it especially not updating listbox when selected item has been edited. Also when creating and freeing objects in the FormCreate and FormDestroy that are referenced by design time defined bindings you might experience some problems. Make sure you handle those objects in the constructor (before inherited) and destructor (after inherited) for the bindings to recognize them correctly.

Data templates:
This piece came from another project (which I will let you know about shortly) but made perfect sense for the collection support. When you add a list of objects to some control. How should the control know what data to display? This is what data templates are for. You specify what class the template is for and what data is displayed. If you look at the code you might recognize where they originally came from.

Tuesday, May 3, 2011

IDE support for data bindings

Some of the coolest techniques lose their attraction when they are not easy to use or if you have to write to much code every time you want to use them. So often there are IDE plugins, wizards or tools of all kinds to make programmers life easier.

I was thinking the same about the data bindings. Sure, every binding is just one line of code at least and adding that controls unit to the uses. But wouldn't it be much more awesome and true RAD if you could set up your bindings just via object inspector? Good news, you can!

When I started thinking about design time support I was remembering that I had seen some magically appearing properties in the object inspector when I put some controls on a TFlowPanel. Also I remembered something about TGlassFrame when it was introduced in Delphi 2007. So I started looking for some articles and I found them, explaining how they managed to introduce that new property without breaking existing classes.
I will not go into detail here but if you interested I recommend to read Hallvards and Allens posts. So the important thing about the design ide is: you can add your own properties for the object inspector you can specify where the values come from (and of course you can remove properties). TEdit for example did not have any additional field or property (except the subclassed controls from the extra unit but that was runtime only).

So where do we take the value from that we can edit in the OI? There is a component now called TBindingGroup that you can add to your form that serves as a container to all the bindings that are created. There is no additional property in the OI until you place one on your form. From now on you can specify the source object and property, the binding mode and the update triggers for the components that are specified to support bindings. Everything is saved inside the binding group and also saved in the dfm file. And the binding group serves one more purpose. If you place it on your form you don't have to add those extra unit to your uses clause since it does so automatically. This is also done by registering your own TSelectionEditor descendants in the design time package.

For a detailed description about adding custom properties to your classes in the IDE I suggest to read this nice article.

So this is what you see when you have placed the binding group component on your form.



Another new feature is that bindings now use a default value converter if the source and target properties have different types if not specified otherwise. That default converter does not convert many data types yet but for the most common uses like showing date/time values in labels or setting numeric values in an edit it is enough.




The full library is avaible here. Just compile and install the package, set the library path and you are ready to use data bindings in your projects.