9

I have an interface.

type IProgressObserver = interface(IInterface)
    procedure ReportProgress(Progress:Integer);
    procedure ReportError(Message:string);
end;

I have implemented the interface using a named class, as follows:

type TProgressObserver=class(TInterfacedObject, IProgressObserver)    
    procedure ReportProgress(Progress:Integer);
    procedure ReportError(Message:string);
end;

... implementation of methods go here .....

addProgressObserver(TProgressObserver.Create);

Is it possible to create an instance of this interface without declaring a class? Something like this (imaginary) code, that would do the same thing as above:

 addProgressObserver(IProgressObserver.Create()
 begin
   procedure ReportProgress(Progress:Integer)
   begin
     ShowMessage('Progress Observed!');
   end

   procedure ReportError(Message:string)
   begin
     Log(Message);
   end
 end;);

Delphi has anonymous procedures, but does it have anonymous classes??

I found this similar question, but it's in Java.

I am using Delphi 2010

2 Answers 2

17

You can get pretty anonymous, implementing the interface using anonymous methods. But you don't get actual compiler support for this, you'll have to declare all the anonymous method types yourself, then implement the actual "anonymous" class. Given your IProgressObserver interface, the implementation would look something like this:

type
  // This is the interface we'll be dealing with.
  IProgressObserver = interface(IInterface)
    procedure ReportProgress(Progress:Integer);
    procedure ReportError(Message:string);
  end;

  // This will help us anonymously create implementations of the IProgressObserver
  // interface.
  TAnonymousObserverImp = class(TInterfacedObject, IProgressObserver)
  type
    // Declare reference types for all the methods the interface needs.
    TReportProgressProc = reference to procedure(Progress:Integer);
    TReportErrorProc = reference to procedure(Message:string);
  strict private
    FReportProgressProc: TReportProgressProc;
    FReportErrorProc: TReportErrorProc;

    // Actual implementation of interface methods.
    procedure ReportProgress(Progress:Integer);
    procedure ReportError(Message:string);
    // private constructor, so we'll forced to use the public "Construct" function
    constructor Create(aReportProgressProc: TReportProgressProc; aReportErrorProc: TReportErrorProc);
  public
    // This takes the required anonymous methods as parameters and constructs an anonymous implementation
    // of the IProgressObserver interface.
    class function Construct(aReportProgressProc: TReportProgressProc; aReportErrorProc: TReportErrorProc): IProgressObserver;
  end;

{ TAnonymousObserverImp }

class function TAnonymousObserverImp.Construct(
  aReportProgressProc: TReportProgressProc;
  aReportErrorProc: TReportErrorProc): IProgressObserver;
begin
  // Call the private constructor
  Result := TAnonymousObserverImp.Create(aReportProgressProc, aReportErrorProc);
end;

constructor TAnonymousObserverImp.Create(
  aReportProgressProc: TReportProgressProc; aReportErrorProc: TReportErrorProc);
begin
  inherited Create;
  // We simply save the references for later use
  FReportProgressProc := aReportProgressProc;
  FReportErrorProc := aReportErrorProc;
end;

procedure TAnonymousObserverImp.ReportError(Message: string);
begin
  // Delegate to anonymous method
  FReportErrorProc(Message);
end;

procedure TAnonymousObserverImp.ReportProgress(Progress: Integer);
begin
  // Delegate to anonymous method
  FReportProgressProc(Progress);
end;

Once all that code is in place you'll be able to write code like this:

var i: IProgressObserver;
begin
  i := TAnonymousObserverImp.Construct(
    procedure (Progress:Integer)
    begin
      // Do something with Progress
    end
    ,
    procedure (Message:string)
    begin
      // Do something with Message
    end
  )
end;

Looks pretty anonymous to me! Given the implementation of anonymous methods in Delphi it's also fairly fast and effective.

Sign up to request clarification or add additional context in comments.

11 Comments

Wow! Great answer (assuming it works that is.. I haven't tested it). Of course, it's a lot more code if you are only creating an instance once (which I am). In my case it's a lot easier to just create a named class, but if you are writing a 3rd party library used by millions of programmers, this would be the way to go. I wonder if all that boilerplate could be auto-generated?
@awmross, of course it works, I test my code before posting it! Automating boilerplate-generation shouldn't be much of a problem, but it'd be better if the compiler did it.
Whilst this is certainly clever, I'm struggling to see when this would be particularly useful.
@David, I'm using something like this to implement enumerators, and it's very handy. The VCL itself does the same in TDelegatedComparer<T>, and I'm sure there are other examples.
@David, there is some pain, especially for smallish interfaces like OP's sample: you need to declare a class and a few methods+implementation, and none of that can be local to the procedure that actually needs the interface instance. Using such anonymous implementations keeps the implementation where it's logically needed and doesn't pollute the namespace. I'll give the TDelegatedComparer<T> example again: Boy did I hate the global functions required for pre-generics TList.Sort() calls!
|
6

Short answer I'm afraid: sorry, no, Delphi doesn't have anonymous classes.

2 Comments

Although it looks like Prism does: prismwiki.codegear.com/en-w/…
Prism is not Delphi

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.