I have this record (BTW it could also be a class, but with records this code makes more sense):
interface
type
TMyRecord = record
A: Integer;
constructor Initialize(V: Integer);
procedure InitOne;
end;
implementation
constructor TMyRecord.Initialize(V: Integer);
begin
A := V;
end;
(implementation of method InitOne omitted for now).
As I know them, record constructors are callable both in a functional form, like conventional constructors for classes, or in a procedural form, directly on a record variable (reference: Record constructors in Delphi).
Giving that, this code compiles and works as expected:
procedure DoSomething;
var
pMyRec: TMyRecord;
begin
pMyRec.Initialize(1); // constructor called in procedural form
pMyRec := TMyRecord.Initialize(1); // constructor called in functional form
end;
While this implementation of InitOne doesn't:
procedure TMyRecord.InitOne;
begin
Self.Initialize(1); // constructor called in procedural form <-- E2382
Self := TMyRecord.Initialize(1); // constructor called in functional form
end;
Why? Shouldn't Self.Initialize(1) be identical to pMyRec.Initialize(1), both called as a procedure acting on its "instance"?
...or vice versa. Let's suppose two classes on which I have no control, both inherit from the same base class:
TDataSet1 = class(TDataSet)
...
end;
TDataSet2 = class(TDataSet)
...
end;
I have an interface declaration like this:
IMyDataSet = interface
procedure MyProc;
end;
Then I have two classes that inherit from the previous ones and that implement my interface:
TMyDataSet1 = class(TDataSet1, IMyDataSet)
procedure MyProc;
end;
TMyDataSet2 = class(TDataSet2, IMyDataSet)
procedure MyProc;
end;
Now my problem is: i have a bunch of procedures and functions which must accept as parameter an object which can be an instance of both my classes.
I don't need to access properties or methods specific to my two classes or to the ancestor ones, only those from the base class TDataSet and those declared in the interface IMyDataSet.
If I declare a procedure like this:
procedure Foo(ADataSet: TDataSet);
I can only call methods from TDataSet class.
If instead I declare the procedure in this way:
procedure Foo(ADataSet: IMyDataSet);
I can see only methods that belong to that interface.
Is there a way so that I can see both TDataSet and IMyDataSet methods on the reference I pass to the procedure?
You can declare parameter as interface and then typecast it to object reference inside method. (This kind of typecasting works in Delphi 2010 and newer)
procedure Foo(ADataSet: IMyDataSet);
var
LDataSet: TDataSet;
begin
LDataSet := TDataSet(ADataSet);
...
end;
Note: If IMyDataSet interface is not implemented on TDataSet class above typecast will fail without raising exception and return nil.
You can also use as operator to typecast, but in that case failure raises exception.
LDataSet := ADataSet as TDataSet;
Another option is to pass parameter as object instance and then retrieve interface from object. In that case your interface must have GUID.
IMyDataSet = interface
['{XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}'] // replace with actual GUID
procedure MyProc;
end;
procedure Foo(ADataSet: TDataSet);
var
LDataSet: IMyDataSet;
begin
if Supports(ADataSet, IMyDataSet, LDataSet) then
begin
...
end;
end;
What is the difference between
TFuncOfIntToString = reference to function(x: Integer): string;
and
TFuncOfIntToString = function(x: Integer): string of object;
I use the of object
Let us consider the following three type declarations:
TProcedure = procedure;
TMethod = procedure of object;
TAnonMethod = reference to procedure;
These are all very similar to each other. In terms of calling instances of each of these three types, the calling code is identical. The differences arise in what can be assigned to variables of these types.
Procedural types
TProcedure is a procedural type. You can assign to a variable of type TProcedure something of this form:
procedure MyProcedure;
begin
end;
This is a non object-oriented procedure. You cannot assign an instance or class method to a TProcedure variable. However, you can assign a static class method to a TProcedure variable.
Method pointers
TMethod is a method pointer. This is indicated by the presence of of object. When you have a variable of type TMethod you must assign either:
A instance method of an instantiated object, or
A class method.
So you can assign either of these:
procedure TMyClass.MyMethod;
begin
end;
class procedure TMyClass.MyClassMethod;
begin
end;
The big difference between a procedural type and a method pointer is that the latter contains a reference to both code and data. A method pointer is often known as a two-pointer procedural type. A variable that contains a method pointer contains references to the code and the instance/class to call it on.
Consider the following code:
var
instance1, instance2: TMyClass;
method1, method2: TMethod;
....
method1 := instance1.MyMethod;
method2 := instance2.MyMethod;
Now, although method1 and method2 refer to the same piece of code, they are associated with different object instances. So, if we call
method1();
method2();
We are invoking MyMethod on the two distinct instances. That code is equivalent to:
instance1.MyMethod();
instance2.MyMethod();
Anonymous methods
Finally we come to anonymous methods. These are even more general purpose than procedural types and method pointers. You can assign any of the following to a variable defined using the reference to syntax:
A plain non object-oriented procedure.
An instance method of an instantiated class.
A class method.
An anonymous method.
For example:
var
AnonMethod: TAnonMethod;
....
AnonMethod := MyProcedure; // item 1 above
AnonMethod := instance1.MyMethod; // item 2
AnonMethod := TMyClass.MyClassMethod; // item 3
Anonymous methods, item 4 above, are those declared in-line in your code. For example:
var
AnonMethod: TAnonMethod;
....
AnonMethod := procedure
begin
DoSomething;
end;
The biggest benefit of anonymous methods when compared to the procedural types and method pointers is that they allow for variable capture. For example consider the following short program to illustrate:
{$APPTYPE CONSOLE}
program VariableCapture;
type
TMyFunc = reference to function(X: Integer): Integer;
function MakeFunc(Y: Integer): TMyFunc;
begin
Result := function(X: Integer): Integer
begin
Result := X*Y;
end;
end;
var
func1, func2: TMyFunc;
begin
func1 := MakeFunc(3);
func2 := MakeFunc(-42);
Writeln(func1(4));
Writeln(func2(2));
Readln;
end.
This has the following output:
12
-84
The first is anonymous method, the second is ordinary method.
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
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.
Short answer I'm afraid: sorry, no, Delphi doesn't have anonymous classes.
I'd like to pass a method of a class as callback to a WinAPI function. Is this possible and if yes, how?
Example case for setting a timer:
TMyClass = class
public
procedure TimerProc(Wnd:HWND; uMsg:DWORD; idEvent:PDWORD; dwTime:DWORD);
procedure DoIt;
end;
[...]
procedure TMyClass.DoIt;
begin
SetTimer(0, 0, 8, #TimerProc); // <-???- that's what I want to do (last param)
end;
Thanks for your help!
Edit: The goal is to specify a method of this class as callback. No procedure outside the class.
Edit2: I appreciate all your help but as long as the method has no "TMyClass." in front of its name it is not what I am searching for. I used to do it this way but wondered if could stay fully in the object oriented world. Pointer magic welcome.
Madshi has a MethodToProcedure procedure. It's in the "madTools.pas" which is in the "madBasic" package. If you use it, you should change the calling convention for "TimerProc" to stdcall and DoIt procedure would become,
TMyClass = class
private
Timer: UINT;
SetTimerProc: Pointer;
[...]
procedure TMyClass.DoIt;
begin
SetTimerProc := MethodToProcedure(Self, #TMyClass.TimerProc);
Timer := SetTimer(0, 0, 8, SetTimerProc);
end;
// After "KillTimer(0, Timer)" is called call:
// VirtualFree(SetTimerProc, 0, MEM_RELEASE);
I've never tried but I think one could also try to duplicate the code in the "classses.MakeObjectInstance" for passing other procedure types than TWndMethod.
Which version of Delphi are you using?
In recent ones you can use static class methods for this:
TMyClass = class
public
class procedure TimerProc(Wnd:HWND; uMsg:DWORD; idEvent:PDWORD; dwTime:DWORD); stdcall; static;
procedure DoIt;
end;
[...]
procedure TMyClass.DoIt;
begin
SetTimer(0, 0, 8, #TimerProc);
end;
The TimerProc procedure should be a standard procedure, not a method pointer.
A method pointer is really a pair of
pointers; the first stores the address
of a method, and the second stores a
reference to the object the method
belongs to
Edit
This might be as much OOP as you are going to get it. All the nasty stuff is hidden from anyone using your TMyClass.
unit Unit2;
interface
type
TMyClass = class
private
FTimerID: Integer;
FPrivateValue: Boolean;
public
constructor Create;
destructor Destroy; override;
procedure DoIt;
end;
implementation
uses
Windows, Classes;
var
ClassList: TList;
constructor TMyClass.Create;
begin
inherited Create;
ClassList.Add(Self);
end;
destructor TMyClass.Destroy;
var
I: Integer;
begin
I := ClassList.IndexOf(Self);
if I <> -1 then
ClassList.Delete(I);
inherited;
end;
procedure TimerProc(Wnd:HWND; uMsg:DWORD; idEvent:PDWORD; dwTime:DWORD); stdcall;
var
I: Integer;
myClass: TMyClass;
begin
for I := 0 to Pred(ClassList.Count) do
begin
myClass := TMyClass(ClassList[I]);
if myClass.FTimerID = Integer(idEvent) then
myClass.FPrivateValue := True;
end;
end;
procedure TMyClass.DoIt;
begin
FTimerID := SetTimer(0, 0, 8, #TimerProc); // <-???- that's what I want to do (last param)
end;
initialization
ClassList := TList.Create;
finalization
ClassList.Free;
end.
Edit: (as mentioned by glob)
Don't forget to add the stdcall calling convention.
Response to your second edit:
If you want a reply that includes a pointer to a TMyClass instance, you may be out of luck. Fundamentally, the procedure Windows will call has a certain signature and is not an object method. You cannot directly work around that, not even with __closure or procedure of object magic, except as described below and in other answers. Why?
Windows has no knowledge of it being an object method, and wants to call a procedure with a specific signature.
The pointer is no longer a simple pointer - it has two halves, the object instance and the method. It needs to save the Self, as well as the method.
By the way, I don't understand what is wrong with a short dip outside the object-oriented world. Non-OO code is not necessarily dirty if used well.
Original, pre-your-edit answer:
It's not possible exactly as you are trying to do it. The method that SetTimer wants must exactly follow the TIMERPROC signature - see the MSDN documentation. This is a simple, non-object procedure.
However, the method TMyClass.DoIt is an object method. It actually has two parts: the object on which it is called, and the method itself. In Delphi, this is a "procedure of object" or a "closure" (read about procedural types here). So, the signatures are not compatible, and you cannot store the object instance, which you need in order to call an object method. (There are also calling convention problems - standard Delphi methods are implemented using the fastcall convention, whereas TIMERPROC specifies CALLBACK which, from memory, is a macro that expands to stdcall. Read more about calling conventions and especially fastcall.)
So, what do you do? You need to map your non-object-oriented callback into object-oriented code.
There are several ways, and the simplest is this:
If you only have one timer ever, then you know that when your timer callback is called it is that specific timer that fired. Save a method pointer in a variable that is of type procedure of object with the appropriate signature. See the Embarcadero documentation link above for more details. It will probably look like:
type TMyObjectProc = procedure of object;
var pfMyProc : TMyObjectProc;
Then, initialise pfMyProc to nil. In TMyClass.DoIt, set pfMyProc to #DoIt - that is, it is now pointing at the DoIt procedure in the context of that specific TMyClass instantiation. Your callback can then call that method.
(If you're interested, class variables that are of a procedural type like this are how event handlers are stored internally. The OnFoo properties of a VCL object are pointers to object procedures.)
Unfortunately this procedural architecture is not object-oriented, but it's how it has to be done.
Here's what some full code might look like (I'm not at a compiler, so it may not work as written, but it should be close):
type TMyObjectProc = procedure of object;
var pfMyProc : TMyObjectProc;
initialization
pfMyProc = nil;
procedure MyTimerCallback(hWnd : HWND; uMsg : DWORD; idEvent : PDWORD; dwTime : DWORD); stdcall;
begin
if Assigned(pfMyProc) then begin
pfMyProc(); // Calls DoIt, for the object that set the timer
pfMyProc = nil;
end;
end;
procedure TMyClass.MyOOCallback;
begin
// Handle your callback here
end;
procedure TMyClass.DoIt;
begin
pfMyProc = #MyOOCallback;
SetTimer(0, 0, 8, # MyTimerCallback);
end;
Another way would be to take advantage of the fact your timer has a unique ID. Save a mapping between the timer ID and the the object. In the callback, convert from the ID to the pointer, and call the object's method.
Edit: I've noticed a comment to another answer suggesting using the address of your object as the timer ID. This will work, but is a potentially dangerous hack if you end up having two objects at the same address at different times, and you don't call KillTimer. I've used that method but don't personally like it - I think the extra bookkeeping of keeping a (timer ID, object pointer) map is better. It really comes down to personal style, though.
I've used MakeObjectInstance a few times to do the same.
Here's an article on the subject:
How to use a VCL class member-function as a Win32 callback
TMyClass = class
public
procedure DoIt;
procedure DoOnTimerViaMethod;
end;
var MyReceiverObject: TMyClass;
[...]
procedure TimerProc(Wnd:HWND; uMsg:DWORD; idEvent:PDWORD; dwTime:DWORD); stdcall:
begin
if Assigned(MyReceiverObject) then
MyReceiverObject.DoOnTimerViaMethod;
end;
procedure TMyClass.DoIt;
begin
MyReceiverObject := Self;
SetTimer(0, 0, 8, #TimerProc); // <-???- that's what I want to do (last param)
end;
Not perfect. Watch for the threads, variable overwriting etc. But it does the job.