How to pass method of arbitrary type into a procedure and identify it? - delphi

I have a thread library which has three constructors for three different method types. I want them to be merged into one and some kind of logic to tell them apart inside the constructor. Is it possible? As there is TValue for values and such, is there a similar thing for method types?
I have the following types supported for now;
TAgThreadMethod1 = procedure of object;
TAgThreadMethod2 = procedure;
TAgThreadMethod3 = procedure(const AThread: TAgThread) of object;
and the constructors are like so:
constructor Create(const AOnRun: TAgThreadMethod1); overload; virtual;
constructor Create(const AOnRun: TAgThreadMethod2); overload; virtual;
constructor Create(const AOnRun: TAgThreadMethod3); overload; virtual;
For reference, I don't want the user to have the ability to change the worker method at a later time after the construction at all. So if a solution exists which can do something like this in a single constructor, is also welcome;
constructor Create
(const AOnRun: [Some type which can hold arbitrary method types]);
begin
// code to identify the method contained in AOnRun.
// if supported, assign it the correct handler.
end;

There isn't any good way to do this, because the whole point of a method pointer is to be invoked at some later point, and you can't do that unless you know its signature. So losing the distinction between signatures is very counterproductive.
If you only want to have to store one type of call inside your object, you could make the three constructors each create an anonymous method with a unified signature that wraps calls to the three types, and just store that instead of having to deal with multiple distinct method types. But what you're asking for, specifically, won't work.

I think that the best that you can do is have a constructor that accepts the most general form of the procedural type. That is TProc<TAgThread>. This will be the master constructor, the only virtual constructor. You can then delegate the other constructors to the master constructors.
To recap, the declaration in SysUtils is:
type
TProc<T> = reference to procedure(Arg1: T);
So your master constructor is:
constructor Create(AOnRun: TProc<TAgThread>); overload; virtual;
The other constructors are not virtual and might look like this:
constructor Create(AOnRun: TAgThreadMethod1); overload;
Implemented as:
constructor TMyClass.Create(AOnRun: TAgThreadMethod1);
begin
Create(
procedure(Thread: TAgThread)
begin
AOnRun();
end;
);
end;
The master constructor, the virtual one, does all the work. The other constructors, the non-virtual ones, adapt their arguments to fit that of the master constructor.

It is possible, but not with only a TValue.
Instead of passing the method itself, you could pass it as a TRttiMethod like this: MyRegisterMethod(TRttiContext.GetType(TMyClassType).GetMethod('MyMethodName'));
If you want to pass all constructors you will need to use a loop like this:
for MyMethod in TRttiContext.GetType(TMyClassType).GetMethods do
if MyMethod.IsConstructor then // As in your example you only want constructors
MyRegisterMethod(MyMethod);
Later, you can call this method like this: MyRegisteredMethod.Invoke(nil, MyMethodParams). MyMethodParams is an array of TValue, which you will need to provide. This can be stored in a TValue itself (although it might be easier to just store them in a TArray). Note that you will only want to use nil in the invoke in case of a class method.
If you want to make sure the parameters are OK, you can verify them by looking them up in MyRttiMethod.GetParameters and compare their actual types to the actual types of the TValues in the array of TValue. This can also be used to find the correct method as well.

Related

FreePascal RTTI. Is there a way to invoke method?

I'm trying to find out if there is a way to do things similar to Delphi's enhanced RTTI features.
As far as I know FPC doesn't provide RTTI features which appeared in Delphi since Delphi 2010. But I'd like to find some way to do a few tricks during runtime.
Using typinfo unit in FPC I can do such things as:
get Object published property list - via getPropList from typinfo unit;
get/set value of the Object's published property - via GetPropValue(...): Variant/SetPropValue(...Value: Variant);
get published method - via MethodAddres;
But I haven't found a way to do things like:
call methods;
call constructors, or create Objects;
Update: the problem with constructors is much like methods one - I want to have a way to pass different params in it:
// concept of code
type
TClass = class of TObject;
TMyClass1 = class
public
constructor Create(Param1: Integer; Param2: string); override;
end;
TMyClass2 = class
public
constructor Create(ObjectParam: Object); override;
end;
TParams = array of Variant;
var
Classes: array of TClass
Instances: array of Object;
ParamArray: array of TParams;
...
For I := 0 to Count-1 do
begin
LocalConstructor := #(Classes[I].Create);
Instances[I] := CallConstructor(LocalConstructor, ParamArray[I]);
end;
So I need to call constructor without knowing its signature.
So my problem is to call an Object's method and pass some parameters to it. It could look like function CallMethod(Instance: Object; MethodName: String; Params: array of Variant): Variant;
If I'm not mistaken it could be solved via Delphi's 2010+ RTTI. But before using enhanced Delphi's RTTI I'd like to understand is it possible in FPC.
In other words my current problem is pass arguments to a routine.
I know it can be done using this scheme:
type
TmyProc = procedure CallMe(x: byte);
...
var proc: TmyProc;
...
proc := pointerToFunc^;
proc(0);
But I need to implement it without knowing count and types of parameters (during compile time).
There are a few links related to the topic:
Delphi: Call a function whose name is stored in a string
http://www.swissdelphicenter.ch/torry/showcode.php?id=1745
The second article (http://www.swissdelphicenter.ch/torry/showcode.php?id=1745) describes a way to pass arguments to a routine imported from DLL by name. Which is almost that I need I suppose. But I'm not sure that way is reliable.
Maybe there's any library, which implements these things using "old" typinfo unit (without RTTI unit)?
Also I'm interested in a way to create some kind of universal event handlers - procedures which can be assigned to different events (with different sets of parameters) e.g.:
procedure myEventHandler(params: array of variant);
...
Button.OnClick := myEventHandler;
Button.OnMouseMove := myEventHandler;
is this possible? Or at least something similar to it?
You can call methods, even not published, using MethodAddress, but it's up to you to ensure correct argument list.
You can call constructors using metaclasses (class references), example of it could be seen in TCollection: you pass class of your collection item at runtime and then it can be created when needed. By defining abstract class with virtual (and probably abstract) constructor, you can come up with argument list you wish, some example here.
AFAIK there is no way to determine argument list at runtime, but if you design both the methods to call and caller itself, there are many ways you can implement similar behavior.
For example, you pass variant open array (Array of const), as it's done in Format(), so number of arguments and its type may vary. But even having one and only pointer as the argument, you sure can pass as many as you want, all you need to do is to come up with some class to which it will lead.

How to free an object which is in a record?

Here I have a tricky situation, I guess. I need to be able to free an object which is a field of a record. I would normally write the cleanup code in the destructor, if it was a class. But since record types can't introduce a "destructor", how would it be possible to call TObject(Field).Free; ?
There'll be two types of usage I predict:
Replacing the record with a new one.
I think this usage would be easy to implement. Since records are value types and so they are copied on assignment, I can overload the assigning operator and free the objects owned by old record.
( Edit: Assignment overloading wasn't able. That's a new info to me.. )
Exiting the scope where record variable defined.
I can think of a private method that frees the objects and this method could be called on scope excitation manually. BUT, here is the same question: How to make it more recordly? This behaviour kind of feels like a class...
Here is a sample (and obviously not the intended usage):
TProperties = record
... some other spesific typed fields: Integers, pointers etc..
FBaseData: Pointer;
FAdditionalData: TList<Pointer>;
//FAdditionalData: array of Pointer; this was the first intended definition
end;
Assume,
FAdditionalData:=TList<Pointer>.Crete;
called in record constructor or manually in record variable scope by accessing the field publicly like
procedure TFormX.ButtonXClick(Sender: TObject);
var
rec: TProperties;
begin
//rec:=TProperties.Create(with some parameters);
rec.FAdditionalData:=TList<Pointer>.Create;
//do some work with rec
end;
After exiting the ButtonClick scope the rec is no more but a TList still keeps its existance which causes to memory leaks...
If all you have in the record is an object reference, then you can't get the compiler to help you. You are in sole charge of the lifetime of that object. You cannot overload the assignment operator, and you don't get any notification of scope finalisation.
What you can do though is to add a guard interface that will manage the lifetime of the object.
TMyRecord = record
obj: TMyObject;
guard: IInterface;
end;
You need to make sure that TMyObject manages its lifetime by reference counting. For example by deriving from TInterfacedObject.
When you initialise the record you do this:
rec.obj := TMyObject.Create;
rec.guard := rec.obj;
At this point, the guard field of the record will now manage your object's lifetime.
In fact, if you want to push this idea further, you can build a dedicated class to guard the lifetime of objects. That then no longer constrains you to implement IInterface on your class. There are plenty of examples on the web that illustrate the technique. For example I offer Jarrod Hollingworth's article titled Smart Pointers, and Barry Kelly's titled Reference-counted pointers, revisited. There are many more out there. It's an old trick!
Note however, that what you have here is a strange hybrid of value type and reference type. On the face of it, records are value types. However, this one acts like a reference type. If you have other fields in the record that are value types then that would be even more confusing. You'll need to be very aware of this issue when you work with such a record.
On the face of it, without knowing more about your design, I'd be inclined to advise you not to put object references in records. They fit better inside reference types, i.e. classes.
I remember that someone created a class named TLifetimeWatcher. Basically, it looks like:
TLifetimeWatcher = class(TInterfacedObject)
private
fInstance: TObject;
fProc: TProc;
public
constructor Create(instance: TObject); overload;
constructor Create(instance: TObject; proc: TProc); overload;
destructor Destroy; override;
end;
// The (cleanup) proc will be executed in the destructor if assigned, otherwise the instance will be freed by invoking the Free method.
https://docwiki.embarcadero.com/RADStudio/Sydney/en/Custom_Managed_Records
THeaderStruct = record
private
public
class operator Initialize (out Header: THeaderStruct);
class operator Finalize (var Header: THeaderStruct);
end;

How to make sure a future inheritance overrides a procedure?

I'm writing a class with some virtual/abstract procedures which I expect to get overridden. However they might not be overridden as well, which is also fine. The problem is finding out whether one of these procedures was actually overridden or not. If they're not overridden, I shouldn't try to call those procedures, and need to go about something different instead. If I try to call one of them and isn't overridden, I get Abstract Error.
Is there a way I can detect whether these procedures were overridden or not?
Here's a sample of how they're declared:
type
TMyClass = class(TObject)
protected
procedure VProc; virtual;
procedure VAProc; virtual; abstract;
end;
You can do something like this. Note that I've removed "abstract". It may work with "abstract" in place, but I haven't tried that.
type
TMyClass = class(TObject)
protected
procedure VProc; virtual;
procedure VAProc; virtual; //abstract;
end;
function GetVAProcAddress(Instance: TMyClass): pointer;
var
p: procedure of object;
begin
p := Instance.VAProc;
result := TMethod(p).Code;
end;
//in one of the TMyClass methods you can now write:
if GetVAProcAddress(self) <> #TMyClass.VAProc then
I think this is the wrong approach, it smells really really bad.. Some suggestions:
Use non-abstract methods that do what you want to do when they are not overridden.
Use events instead of methods. It's easy to check whether they have been assigned.
A method that may or may not be overridden is not an abstract method, it is merely virtual.
An abstract method is one that has no base implementation and for which an implementation must be provided by a descendant.
In your case, simply declare them as virtual and provide them with the NO-OP (No operation) default implementation that your design dictates:
type
TMyBaseClass = class
protected
procedure SomeProc; virtual;
end;
procedure TMyBaseClass.SomeProc;
begin
// NO-OP
end;
Note - this illustrates my own personal convention of documenting a deliberate NO-OP, rather than just leaving an empty implementation.
Any shennanigans you go through to attempt to detect whether a declared abstract method has been overridden or not and to call it - or not - on the basis of that test is likely to cost more time than simply calling a NO-OP implementation. Plus, should you ever need to introduce an implementation in that base class you don't have to change the method from abstract to non-abstract (possibly disrupting those "detection" circuits you had w.r.t that method, and certainly rendering their cost as nothing but pure overhead).
Use RTTI to get the method address of the virtual method in question for the class in questions. Compare it to the method address for the same method of the base class. If it is not the same, then the method was overriden.
If you got a line code like this:
lObj := TMyClass.Create;
you will notice that the compiler will output a warning saying that you are constructing instance of 'TMyClass' containing abstract method TMyClass.VAProc.

OO Design: use Properties or Overloaded methods?

Question about OO design.
Suppose I have a base object vehicle. And two descendants: truck and automobile.
Further, suppose the base object has a base method:
Procedure FixFlatTire(); abstract;
When the truck and automobile override the base object's, they require different information from the caller.
Am I better off overloading FixFlatTire like this in the two descendant objects:
Procedure Truck.FixFlatTire( OfficePhoneNumber: String;
NumberOfAxles: Integer): Override; Overload;
Procedure Automobile.FixFlatTire( WifesPhoneNumber: String;
AAAMembershipID: String): Override; Overload;
Or introducing new properties in each of the descendants and then setting them before calling FixFlatTire, like this:
Truck.OfficePhoneNumber := '555-555-1212';
Truck.NumberOfAxles := 18;
Truck.FixFlatTire();
Automobile.WifesPhoneNumber := '555-555-2323';
Automobile.AAAMembershipID := 'ABC';
Automobile.FixFlatTire();
If the data in question are logically part of the descendant class (if you might use them in other contexts) it makes sense to add the properties directly to the descendant class.
If they apply strictly to the FixFlatTire method, it makes more sense to specify them as arguments to that function.
If you supply a different method signature in a descendant class, that is not (to my knowledge) a case of overloading. You are simply overriding the original function with a new function with different arguments. Overloading is when two identically named functions are available, distinguished by different signatures.
[Edit]
Looking at your arguments a bit closer, here are some more thoughts:
NumberOfAxles pretty clearly seems to be a property of TTruck.
PhoneNumber and AAAMembershipID seem to me to be properties of a class you don't have yet, TOwner (with possible descendant classes TCorporateOwner and TIndividualOwner). Then, a TOwner reference can become a property of TVehicle or an argument to FixFlatTire() (although I imagine it would better belong as a property of the TVehicle).
The real error is
FixFlatTire(); abstract;
It certainly should be
FixFlatTire(); virtual; abstract;
to enable polymorphic behavior.
You should not overload virtual methods, only override preserving method's arguments.
Update
You should not and can not overload virtual methods. The following code does not even compile:
type
TVehicle = class
procedure FixFlatTire(); virtual; abstract;
end;
TTruck = class(TVehicle)
Procedure FixFlatTire( OfficePhoneNumber: String;
NumberOfAxles: Integer); Override; Overload;
end;
TAutomobile = class(TVehicle)
Procedure FixFlatTire( WifesPhoneNumber: String;
AAAMembershipID: String); Override; Overload;
end;
You should preserve virtual method's arguments while overriding the virtual method.
So the answers is - the first option (overloading) is just impossible.
I wouldn't use the latter, as it's easy for someone to set some properties and forget to later call the method. The first is a problem too though, because you don't have a matching signature for each method in the base class.
Most problems in OOP can be solved with another layer of abstraction. You could have something like this in the base class, shared by both Automobile and Truck.
procedure FixFlatTire(TireProvider: ITireProvider); abstract; virtual;
ITireProvider can be subclassed with an OfficeTireProvider and AAATireProvider, which contain the respective properties you need to set for each, and they can override any members of ITireProvider needed to do the actual tyre fixing.
The approach with properties is pointless. You can't use polymorphism properly since the functions take different parameters. You should just have distinct methods in the subclasses with the appropriate parameters.
Now, if you come back with a more complex version in which you only hold a reference to the base class then a different design would be called for, but it would be neither of the ones you have offered so far.

Reintroducing functions in Delphi

What was the motivation for having the reintroduce keyword in Delphi?
If you have a child class that contains a function with the same name as a virtual function in the parent class and it is not declared with the override modifier then it is a compile error. Adding the reintroduce modifier in such situations fixes the error, but I have never grasped the reasoning for the compile error.
If you declare a method in a descendant class that has the same name as a method in an ancestor class then you are hiding that ancestor method — meaning if you have an instance of that descendant class (that is referenced as that class) then you will not get the behavior of the ancestor. When the ancestor's method is virtual or dynamic, the compiler will give you a warning.
Now you have one of two choices to suppress that warning message:
Adding the keyword reintroduce just tells the compiler you know you are hiding that method and it suppresses the warning. You can still use the inherited keyword within your implementation of that descended method to call the ancestor method.
If the ancestor's method was virtual or dynamic then you can use override. It has the added behavior that if this descendant object is accessed through an expression of the ancestor type, then the call to that method will still be to the descendant method (which then may optionally call the ancestor through inherited).
So difference between override and reintroduce is in polymorphism. With reintroduce, if you cast the descendant object as the parent type, then call that method you will get the ancestor method, but if you access it the descendant type then you will get the behavior of the descendant. With override you always get the descendant. If the ancestor method was neither virtual nor dynamic, then reintroduce does not apply because that behavior is implicit. (Actually you could use a class helper, but we won't go there now.)
In spite of what Malach said, you can still call inherited in a reintroduced method, even if the parent was neither virtual nor dynamic.
Essentially reintroduce is just like override, but it works with non-dynamic and non-virtual methods, and it does not replace the behavior if the object instance is accessed via an expression of the ancestor type.
Further Explanation:
Reintroduce is a way of communicating intent to the compiler that you did not make an error. We override a method in an ancestor with the override keyword, but it requires that the ancestor method be virtual or dynamic, and that you want the behavior to change when the object is accessed as the ancestor class. Now enter reintroduce. It lets you tell the compiler that you did not accidentally create a method with the same name as a virtual or dynamic ancestor method (which would be annoying if the compiler didn't warn you about).
There are lots of answers here about why a compiler that lets you hide a member function silently is a bad idea. But no modern compiler silently hides member functions. Even in C++, where it's allowed to do so, there's always a warning about it, and that ought to be enough.
So why require "reintroduce"? The main reason is that this is the sort of bug that can actually appear by accident, when you're not looking at compiler warnings anymore. For example, let's say you're inheriting from TComponent, and the Delphi designers add a new virtual function to TComponent. The bad news is your derived component, which you wrote five years ago and distributed to others, already has a function with that name.
If the compiler just accepted that situation, some end user might recompile your component, ignore the warning. Strange things would happen, and you would get blamed. This requires them to explicitly accept that the function is not the same function.
The RTL uses reintroduce to hide inherited constructors. For example, TComponent has a constructor which takes one argument. But, TObject has a parameterless constructor. The RTL would like you to use only TComponent's one-argument constructor, and not the parameterless constructor inherited from TObject when instantiating a new TComponent. So it uses reintroduce to hide the inherited constructor. In this way, reintroduce is a little bit like declaring a parameterless constructor as private in C#.
First of all, "reintroduce" breaks the inheritance chain and should not be used, and I mean never ever. In my entire time I worked with Delphi (ca 10 years) I've stumbled upon a number of places that do use this keyword and it has always been a mistake in the design.
With that in mind here's the simplest way it works:
You have like a virtual method in a base class
Now you wanna have a method that has the exact same name, but maybe a different signature. So you write your method in the derived class with the same name and it will not compile because the contract is not fulfilled.
You put the reintroduce keyword in there and your base class does not know about your brand new implementation and you can use it only when accessing your object from a directly specified instance type. What that means is toy can't just assign the object to a variable of base type and call that method because it's not there with the broken contract.
Like I said it's pure evil and must be avoided at all cost (well, that's my opinion at least). It's like using goto - just a terrible style :D
The purpose of the reintroduce modifier is to prevent against a common logical error.
I will assume that it is common knowledge how the reintroduce keyword fixes the warning and will explain why the warning is generated and why the keyword is included in the language. Consider the delphi code below;
TParent = Class
Public
Procedure Procedure1(I : Integer); Virtual;
Procedure Procedure2(I : Integer);
Procedure Procedure3(I : Integer); Virtual;
End;
TChild = Class(TParent)
Public
Procedure Procedure1(I : Integer);
Procedure Procedure2(I : Integer);
Procedure Procedure3(I : Integer); Override;
Procedure Setup(I : Integer);
End;
procedure TParent.Procedure1(I: Integer);
begin
WriteLn('TParent.Procedure1');
end;
procedure TParent.Procedure2(I: Integer);
begin
WriteLn('TParent.Procedure2');
end;
procedure TChild.Procedure1(I: Integer);
begin
WriteLn('TChild.Procedure1');
end;
procedure TChild.Procedure2(I: Integer);
begin
WriteLn('TChild.Procedure2');
end;
procedure TChild.Setup(I : Integer);
begin
WriteLn('TChild.Setup');
end;
Procedure Test;
Var
Child : TChild;
Parent : TParent;
Begin
Child := TChild.Create;
Child.Procedure1(1); // outputs TChild.Procedure1
Child.Procedure2(1); // outputs TChild.Procedure2
Parent := Child;
Parent.Procedure1(1); // outputs TParent.Procedure1
Parent.Procedure2(1); // outputs TParent.Procedure2
End;
Given the above code both of the procedures in TParent are hidden. To say they are hidden means that the procedures can not be called through the TChild pointer. Compiling the code sample produces a single warning;
[DCC Warning] Project9.dpr(19): W1010 Method 'Procedure1' hides virtual method of base type 'TParent'
Why only a warning for the virtual function and not the other? Both are hidden.
A virtue of Delphi is that library designers are able to release new versions without fear of breaking the logic of existing client code. This contrasts to Java where adding new functions to a parent class in a library is fraught with danger because classes are implicitly virtual. Lets say that TParent from above lives in a 3rd party library, and the library manufacture releases the new version below.
// version 2.0
TParent = Class
Public
Procedure Procedure1(I : Integer); Virtual;
Procedure Procedure2(I : Integer);
Procedure Procedure3(I : Integer); Virtual;
Procedure Setup(I : Integer); Virtual;
End;
procedure TParent.Setup(I: Integer);
begin
// important code
end;
Imagine we had the following code in our client code
Procedure TestClient;
Var
Child : TChild;
Begin
Child := TChild.Create;
Child.Setup;
End;
For the client it does not matter if the code is compiled against version 2 or 1 of the library, in both cases TChild.Setup is called as the user intends. And in the library;
// library version 2.0
Procedure TestLibrary(Parent : TParent);
Begin
Parent.Setup;
End;
If TestLibrary is called with a TChild parameter, everything works as intended. The library designer have no knowledge of the TChild.Setup, and in Delphi this does not cause them any harm. The call above correctly resolves to TParent.Setup.
What would happen in a equivalent situation in Java? TestClient would work correctly as intended. TestLibrary would not. In Java all functions are assumed virtual. The Parent.Setup would resolve to TChild.Setup, but remember when TChild.Setup was written they had no knowledge of the future TParent.Setup, so they are certainly not going to ever call inherited. So if the library designer intended TParent.Setup to be called it will not be, no matter what they do. And certainly this could be catasrophic.
So the object model in Delphi requires explicit declaration of virtual functions down the chain of child classes. A side effect of this is that it is easy to forget to add the override modifier on child methods. The existence of the Reintroduce keyword is a convenience to the programmer. Delphi was designed so that the programmer is gently persuaded, by the generation of a warning, to explicitly state their intentions in such situations.
tl;dr: Trying to override a non-virtual method makes no sense. Add the keyword reintroduce to acknowledge that you're making a mistake.
Reintroduce tells the compiler you want to call the code defined in this method as an entry point for this class and its descendants, regardless of other methods with the same name in the ancestors’ chain.
Creating a TDescendant.MyMethod would create a potential confusion for the TDescendants in adding another method with the same name, which the compiler warns you about.
Reintroduce disambiguates that and tells the compiler you know which one to use.
ADescendant.MyMethod calls the TDescendant one, (ADescendant as TAncestor).MyMethod calls the TAncestor one. Always! No confusion…. Compiler happy!
This is true whether you want the descendant method to be virtual or not: in both cases you want to break the natural linkage of the virtual chain.
And it does not prevent you from calling the inherited code from within the new method.
TDescendant.MyMethod is virtual: ...but you cannot or don’t want to use the linkage.
You cannot because the method signature is different. You have no other choice as overriding is impossible in this case with return type or parameters not exactly the same.
You want to restart an inheritance tree from this class.
TDescendant.MyMethod is not virtual: You turn MyMethod into a static one at the TDescendant level and prevent further overriding. All classes inheriting from TDescendant will use the TDescendant implementation.
When the ancestor class also has a method with the same name, and it is not necessarily declared virtual, you would see a compiler warning (as you would hide this method).
In other words: You tell the compiler that you know that you hide the ancestor function and replace it with this new function and do so deliberately.
And why would you do this? If the method is virtual in the parent class, the only reason is to prevent polymorphism. Other then that just override and do not call inherited. But if the parent method is not declared virtual (and you cannot change that, because you do not own the code for example), you can inherit from that class and let people inherit from your class without seeing a compiler warning.
This has been introduced to the language because of Framework versions (including the VCL).
If you have an existing code base, and an update to a Framework (for instance because you bought a newer Delphi version) introduced a virtual method with the same name as a method in an ancestor of your code base, then reintroduce will allow you to get rid of the W1010 warning.
This is the only place where you should use reintroduce.
First, as it was said above, you should never ever deliberately reintroduce virtual method. The only sane use of reintroduce is when the author of the ancestor (not you) added a method that goes into conflict with your descendant and renaming your descendant method is not an option. Second, you can easily call the original version of the virtual method even in classes where you reintroduced it with different parameters:
type
tMyFooClass = class of tMyFoo;
tMyFoo = class
constructor Create; virtual;
end;
tMyFooDescendant = class(tMyFoo)
constructor Create(a: Integer); reintroduce;
end;
procedure .......
var
tmp: tMyFooClass;
begin
// Create tMyFooDescendant instance one way
tmp := tMyFooDescendant;
with tmp.Create do // please note no a: integer argument needed here
try
{ do something }
finally
free;
end;
// Create tMyFooDescendant instance the other way
with tMyFooDescendant.Create(20) do // a: integer argument IS needed here
try
{ do something }
finally
free;
end;
so what should be the purpose of reintroducing virtual method other than make things harder to read?
reintroduce allows you to declare a method with the same name as the ancestor, but with different parameters. It has nothing to do with bugs or mistakes!!!
For example, I often use it for constructors...
constructor Create (AOwner : TComponent; AParent : TComponent); reintroduce;
This allows me to create the internal classes in a cleaner fashion for complex controls such as toolbars or calendars. I normally have more parameters than that. Sometimes it is almost impossible or very messy to create a class without passing some parameters.
For visual controls, Application.Processmessages can get called after Create, which can be too late to use these parameters.
constructor TClassname.Create (AOwner : TComponent; AParent : TComponent);
begin
inherited Create (AOwner);
Parent := AParent;
..
end;

Resources