Showing posts sorted by relevance for query TVirtualInterface. Sort by date Show all posts
Showing posts sorted by relevance for query TVirtualInterface. Sort by date Show all posts

Thursday, September 1, 2011

Delphi XE2 - features aside from the hype: TVirtualInterface

While prolly almost everyone was creating fancy FireMonkey or VCL applications for Windows (32-bit and 64-bit), OSX and/or iOS with Delphi XE2 today I took a look at one of my favorite units in the RTL - System.Rtti.pas.

When you look at the RTL Changes for XE2 you will see a new addition to the RTTI - TVirtualInterface. Along with this comes another improvement: RTTI can finally tell the implemented interfaces of a class (and its ancestors). But back to the TVirtualInterface!

Documentation says: "Provides functionality for remote procedure call marshaling. TVirtualInterface creates an implementation of an interface at run time." Wow, this sounds interesting. Further reading states that it's main purpose is SOAP messaging. A client can consume a service with several methods just by calling them through an interface which then "just calls" the remote methods of the service. I think this is awesome because it leads to clear defined interfaces (literally) when working with remote services or other things that just hide behind the interface and which are not necessary to be known. Other things I say...

Some while ago when I came across the Emballo Framework I was impressed by the DLLWrapper which basically imports exported functions of a DLL and provides them through an interface. Of course there have to be some rules like the calling conventions and the parameters have to match. But you can do define an interface like this:

type
  IMyLibrary = interface
    ['{8B47F556-673B-44D6-8F90-09985B3C53E0}']
    function SayHello: string
  end;

And then simply import a DLL which exports this function and just call it. It was a bit rough and actually only supported a few types and not all calling conventions. So I am very happy to have a tool out of the box that makes it possible to write something like this:

if Supports('MyLibrary.dll', IMyLibrary, LMyLibraryIntf) then
  ShowMessage(LMyLibraryIntf.SayHello());

Those of you that worked with .Net in RAD Studio 2007 may know this - it was called Virtual Library Interfaces. I have not tried yet, but I am sure if you have the correct signature in your interfaces methods you can call almost every DLL. Actually the Supports functions does not exist in Delphi but you can find it in the brand new unit DSharp.Core.Plugins.

I uploaded a simple sample how to use this (including the new unit which can also be downloaded from the svn repository).

I also added the DSharp packages for XE2 today (only 32-bit for now, 64-bit compatibility will follow soon). I know there is some issue with the asm code in the DSharp.Core.Events (that has to go for 64-bit anyway) which break bindings for now - but I am working on it. Also more about LiveBindings vs DSharp soon.

Saturday, September 13, 2014

Spring4D 1.1 release and roadmap

Today I am happy to officially announce the release of version 1.1. And also it is the 5th anniversary of Spring4D (at least according to the commit history).

Thanks Paul who started the project and all the others that made Spring4D what it is today:
A modern RTL extension and the most powerful dependency injection container written in Delphi that can compete with those in other languages easily.

For the 1.1 release we have fixed many bugs, refactored and cleaned up the internals of the container and implemented many neat new things. And of course added support for Delphi XE7.

After 5 years and finally getting past version 1.0 we felt it was time to get some official logo for Spring4D to be recognizable and here it is - thanks to Chris Wagner for his help!


New feature - automatic factories

There is one particular feature I am very proud of - and thanks to Philipp Schäfer who had brought me to this idea: automatic factories.

When you are dealing with dependency injection you often have the case that you cannot create everything upfront. Mostly because some information is missing that the user enters during the use of the application. That is when factories and lazy initialization come into play. You obviously created factory classes in the past and registered them into the container so they could be injected into other classes that used them.

You don't have to do that anymore because the container now can create these factories for you!

Let's look at some example:

type
  IMyService = interface
    ['{9C0B02FE-5A69-4409-ACA6-C702CE4D9B44}']
    procedure DoSomething(const msg: string);
  end;

  IDialogService = interface
    ['{A65920CC-E729-4E3B-BD3C-20A9BBDFE753}']
    procedure ShowDialog;
  end;

  TMyService = class(TInterfacedObject, IMyService)
  private
    fAnotherServiceFactory: IFactory<string, IDialogService>;
  public
    constructor Create(const anotherServiceFactory: IFactory<string, IDialogService>);
    procedure DoSomething(const msg: string);
  end;

  TDialogService = class(TInterfacedObject, IDialogService)
  private
    fMsg: string;
  public
    constructor Create(const msg: string);
    procedure ShowDialog;
  end;

constructor TMyService.Create(
  const anotherServiceFactory: IFactory<string, IDialogService>);
begin
  fAnotherServiceFactory := anotherServiceFactory;
end;

procedure TMyService.DoSomething(const msg: string);
begin
  fAnotherServiceFactory(msg).ShowDialog;
end;

constructor TDialogService.Create(const msg: string);
begin
  fMsg := msg;
end;

procedure TDialogService.ShowDialog;
begin
  ShowMessage(fMsg);
end;

Some pretty straightforward code with only one thing that might look unfamilar: IFactory is a new type that can be resolved by the container automatically and comes from the unit Spring.Container.Common and is similar to TFunc but with $M+ which is required for the container to automatically resolve this type using TVirtualInterface.

So how does the registration code look like?

  container.RegisterType<TMyService>;
  container.RegisterType<TDialogService>;
  container.RegisterType<IFactory<string, IDialogService>>.AsFactory;
  container.Build;

  myService := container.Resolve<IMyService>;
  myService.DoSomething('Spring4D rocks!');

The new method AsFactory tells the container to treat this interface or delegate type (if it has method typeinfo on) as factory and it automatically creates the implementation. Any arguments passed are then passed to the container as arguments for the resolution process. That means in this example the string getting passed to the DoSomething method and into the factory is then passed to the container to be injected to the constructor of TDialogService.

What's coming next?

There are several things we want to do in the next couple of months.
  • As you might have seen we have something new in development that is known to some as marshmallow: an ORM that Linas Naginionis contributed to Spring4D. He and Cesar Romero are new on the team and are currently working on the migration and integration into the library.
  • Honza has been working on a better logging solution that will be used internally by the container and can be used in your applications and will have several backends (for CodeSite, SmartInspect or for simple text or console logs). It also can be easily extended to your needs.
  • I have been working on an easy to use interception (AOP) library that can be integrated into the container or used as standalone to do some nice things - those of you attending the EKON 18 in November in cologne will probably see more of it shown by Nick and me.
Along with these new features we also want to write more documentation and how-to articles introducing you to all the features in Spring4D and show advanced dependency injection techniques.

We are eager for your feedback!

As always your feedback is welcome. Are you using Spring4D in your software? Please let us know! You have ideas how to improve the library or want to contribute? Don't hesitate to contact us.

Wednesday, October 29, 2014

The real power of generics

I just watched the "Effectively Using Generics in Object Pascal" Code Rage 9 session by Ray Konopka, where he showed a great introduction to generics which is mostly about putting things into lists, dictionaries or other data structures. So basically container types what generics are great for.

When someone asked how you can find out the type of T inside your generic type Ray responded that if you need to do that you may be doing something wrong and why that might be necessary because generic types should be type agnostic.

It might be correct if you only think of collection types when you think about generics. And this is what many people do, hence the discussion I have seen in several places why other pascal languages would need generics because they have powerful array support or other excuses.

But this is limited thinking very much. Generics are way more than a tool to build collection types.
You can do things like the multicast events in Spring4D where of course the generic type needs to find out the exact type info of the T in Event<T> to execute the correct code depending on how you are dealing with a event type or an anonymous method type.
Or think about using generics when using the Spring4D dependency injection container. How could we use TContainer.RegisterType<T> or TContainer.Resolve<T> without finding out the exact type. In fact in that API you mostly don't even pass a variable of that type but just use the generic methods as replacement for something like TContainer.RegisterType(TypeInfo(...)).

Want more examples? Sure!
Think of something like Mock<T> where T is then the type you want to create a mock for. You of course need to find out the type info to pass that into the code that does all the rtti magic beneath (like TVirtualInterface). Think of fluent APIs that return T and provide some typesafe way to use that API (which is what the container registration API and mocks do). Hey, even TComparer<T> from System.Generics.Defaults internally looks up what type the T is to call the correct comparison routine depending on the TTypeKind of the type.

I hope that showed some of the examples where generics give you great power beyond that overused "list of something" example. I am sure you can think of more possibilities!

Oh, by the way the answer to the question asked is: you can use TypeInfo(T) or some of the new intrinsic functions to get information of your generic type parameter.