Is it ok to initialize members field before inherited in create? - delphi

Is it ok to initialize members field before calling inherited in create ?
IE:
constructor TMyObject.create(AOwner: TComponent);
begin
fMyField := xxx;
inherited
end;
instead of normal way :
constructor TMyObject.create(AOwner: TComponent);
begin
inherited
fMyField := xxx;
end;
just to know is their is any drawback i didn't see ...

When an instance of a class is instantiated, the memory is allocated and default initialized (e.g. filled with zeros), and then the constructor is called. So, any code in a constructor executes after the default initialization, which would be the one timing issue that you might imagine scuppering what you are doing.
However, code such as yours is usually indicative of a deeper design malaise. How could it matter whether you initialized a value before calling the inherited constructor? There are two reasons I can imagine where you might be tempted to do this:
If the field in question is declared in your derived class, then the only way the ancestor code could access it is by calling a virtual (or dynamic) method. And doing so in a constructor is dangerous because the object is only partially created. That's a big toxic code smell.
If the field in question is declared in the ancestor classes, you might be using this mechanism to in effect pass an argument from derived class to ancestor. That's a rather weird way of doing it. A much more appropriate way would be to use arguments in your constructor.

Related

Delphi Tdictionary inheritance

I try to inherit from Tdictionary and somehow the default comparer is lost. This is what I do in essence:
type
TinpVar = class
end;
TinputVars = class(Tdictionary<string,TinpVar>)
end;
TLVRvars = class(TinputVars)
constructor create;
end;
constructor TLVRvars.create;
begin
inherited;
end;
var LVRvars : TLVRvars;
begin
LVRvars:=TLVRvars.create;
With this construction I get an AV when adding a key/value pair to LVRvars. Eventually I found that this can be prevented by changing the constructor of the inherited class to
constructor TLVRvars.create;
begin
inherited create;
end;
I do not understand why I have to do that. Although my problem is solved, I would still like to know.
In your constructor
inherited;
calls the constructor with identical parameter list to your constructor. Your constructor has no parameters, and so inherited calls the do nothing constructor in TObject. Not only have you lost your comparer, but your instance is missing the rest of the necessary steps in construction.
When you replace it with
inherited Create;
the compiler instead performs normal method resolution. It looks up the class ancestor list and calls the first method which it can. In that case this is:
constructor Create(ACapacity: Integer = 0); overload;
Hence your instance is properly created.
The documentation is here: http://docwiki.embarcadero.com/RADStudio/en/Methods#Inherited
Key excerpts are:
If inherited is followed by the name of a member, it represents a normal method call
and
When inherited has no identifier after it, it refers to the inherited
method with the same name as the enclosing method or, if the enclosing
method is a message handler, to the inherited message handler for the
same message. In this case, inherited takes no explicit parameters,
but passes to the inherited method the same parameters with which the
enclosing method was called. For example:
inherited;
occurs frequently in the implementation of constructors. It calls the
inherited constructor with the same parameters that were passed to the
descendant.
It's pretty weird isn't it. On the face of it, it seems astonishing that different methods are called. The key point though is that plain inherited leads to exact matching of parameter lists. And your method has no parameters.
On the other hand inherited Create is a standard method call. In that latter case, you end up calling a method with one parameter, using the default value for that parameter. So whilst it looks like you are calling a parameterless constructor you are not. You are passing one parameter, ACapacity, and a value of 0.
The comparator is a object that need to be created itself. If you had no constructor in your descended class I would expect the default constructor to be created because you would be implicitly calling the inherited constructor. If you create your own constructor you should always called the inherited Create (in my opinion) to allow the ancestor to do its work - in this case creating default comparator.

override, virtual/dynamic in Delphi constructors

The one with virtual/dynamic
// declare in Child Class
constructor Create; virtual;
constructor TChildClass.Create;
begin
inherited;
end;
The one with override.
// declare in Child Class
constructor Create; override;
constructor TChildClass.Create;
begin
inherited;
end;
The one with nothing
// declare in Child Class
constructor Create;
constructor TChildClass.Create;
begin
inherited;
end;
Are these the same thing? It looks confusing.
Yes, there is a difference, but let's deal with the virtual keyword in more basic OOP terms first, yet still how it applies to Delphi methods.
When you declare a derived (child) class, and implement a method as "override", it means that you're overriding (surprise) the matching method of the base class.
This means that you can write code like this:
var child : TBaseClass;
begin
child := TChildClass.Create; // note that it is stored in TBaseClass variable
child.VirtualMethodDefinedInBaseClassThatHasBeenOverriddenInChildClass;
This will call the method in the child class, even if the variable is defined to be of the base class type. This is the whole purpose of virtual methods, you can access the object through a reference of a more general type, and still call methods that have been written for the particular type of object you're dealing with.
If you have a virtual method in the base class that you chose not to override in the child class, but instead reintroduce, you're effectively replacing it in some cases. Note that in most cases you need to tell the compiler that you really meant to do this, though I'm unsure about what Delphi requires here.
Basically, if your variable is of type TBaseClass, and you call a virtual method on it, that has been reintroduced in the TChildClass, it will still call the method in the base class.
However, if your variable is of type TChildClass, and you call that method on it, you will get the new method instead.
Now, for constructors, in Delphi, it is slightly different.
The point of virtual constructors is to be able to virtually construct objects, and to do that, Delphi also has "class types".
You can say this:
type TClassToUse = class of TBaseClass;
var cls : TClassToUse;
obj : TBaseClass;
begin
cls := TChildClass;
obj := cls.Create;
(note that my Delphi knowledge is a bit rusty here, if anyone spots bugs or glaring problems in the above code, please let me know or just fix it)
Here we store a "class" in a variable, and then ask the class to please construct an object for us. This allows us to switch out which class to create, but we also need to declare the constructors we want to use virtual, otherwise we will have problems.
So in the above code, if you declared the constructor as virtual in TBaseClass, and then override it in TChildClass (which the code is actually using in cls), the overridden constructor is the one that will be used.
If, on the other hand, you don't declare the constructor as virtual, we're back to the base class constructor. Virtual basically means to figure out the right method to execute at runtime, whereas non-virtual will figure it out at compile time.
Reintroduction as described for normal methods above, also works this way.
However, virtual constructors are only used as virtual when used through a class type.
No, static and virtual methods are not the same thing.
And override is a case of virtual method.
http://en.wikipedia.org/wiki/Virtual_function
http://docwiki.embarcadero.com/RADStudio/XE4/en/Methods#Method_Binding
Constructors bring nothing special here - they conform to the same rules as other methods for the question

What's the damage from calling inherited incorrectly?

In searching for a highly intermittent memory corruption in a Delphi XE program, I have found a class constructor which initializes a few fields in the class, and then calls inherited. I believe the initializations were added after the constructor was first written, and accidentally in the wrong place. I have now corrected it to call inherited first. The exceptions from the memory corruption almost always occur in a method of this class.
Question: is it possible that this mistake caused an intermittent memory corruption? In tracing the code, it seems not, but I would really like this fix to be what solves the intermittent issue. That it does not occur for a while after fixing the problem will not prove that it has gone away.
Some code:
Tmyclass = class
ctype : integer;
ts : tstringlist;
th : thandle;
public
Constructor Create;
Destructor Destroy; override;
...
end;
Constructor Tmyclass.Create;
begin
ctype := 3;
doinit;
inherited;
end;
Here are typical steps of an object creation:
Memory allocation of the object instance;
Fill all memory with zero (to initialize all fields, especially string);
Call all nested constructors, beginning with the latest child, letting inherited call every parent - that is why you shall write inherited in both constructors and destructors.
So, inherited calls the parent method - you can even specify a parent level, or call none if you are sure you can do that (but may break the SOLID principles).
In fact, when a constructor is called, there is an hidden parameter added to the method:
Constructors and destructors use the same calling conventions as other
methods, except that an additional Boolean flag parameter is passed to
indicate the context of the constructor or destructor call.
A value of False in the flag parameter of a constructor call indicates
that the constructor was invoked through an instance object or using
the inherited keyword. In this case, the constructor behaves like an
ordinary method. A value of True in the flag parameter of a
constructor call indicates that the constructor was invoked through a
class reference. In this case, the constructor creates an instance of
the class given by Self, and returns a reference to the newly created
object in EAX.
A value of False in the flag parameter of a destructor call indicates
that the destructor was invoked using the inherited keyword. In this
case, the destructor behaves like an ordinary method. A value of True
in the flag parameter of a destructor call indicates that the
destructor was invoked through an instance object. In this case, the
destructor deallocates the instance given by Self just before
returning.
The flag parameter behaves as if it were declared before all other
parameters. Under the register convention, it is passed in the DL
register. Under the pascal convention, it is pushed before all other
parameters. Under the cdecl, stdcall, and safecall conventions, it is
pushed just before the Self parameter.
Source: official Delphi documentation
So you can be sure that, wherever the inherited is called, it will be safely handled. For instance, initialization of fields (reset to 0) will be processed only once, before all constructors are called.
The TObject.Create default constructor (the one called in your inherited line) is just a begin end void block, which does nothing. It is not even necessary/mandatory to call inherited here, but it is a good habit, since if you change your object hierarchy, it may be needed afterall.
Only issue may be if some fields are set inside this inherited method (ctype := 2 e.g.), after having been set in the child - but this is not compiler's fault, this is up to user code!
Initializing some fields before calling the inherited constructor is not necessarily a bug. Sometimes the inherited constructor calls some virtual methods which have been overridden by the descendant and these new implementations rely on those fields to be correctly initialized.
(I am not saying that this is good design, but it's not a bug.)
In Delphi you can initialize object fields before calling inherited constructor (it does not worked in Turbo Pascal or 'old' object model, but it is allowed in Delphi 'new' object model).

Using inherited in the "Create" constructor of an TObject

Rant: Should I call "inherited" in the constructor of a class derived from TObject or TPersistent?
constructor TMyObject.Create;
begin
inherited Create; // Delphi doc: Do not create instances of TPersistent. Use TPersistent as a base class when declaring objects that are not components, but that need to be saved to a stream or have their properties assigned to other objects.
VectorNames := TStringList.Create;
Clear;
end;
Yes. It does nothing, true, but it's harmless. I think there is value in being consistent about always calling the inherited constructor, without checking to see if there is, in fact, an implementation. Some will say that it's worth calling inherited Create because Embarcadero might add an implementation for TObject.Create in the future, but I doubt this is true; it would break existing code which does not call inherited Create. Still, I think it is a good idea to call it for the reason of consistency alone.
I always do this.
If you are refactoring and move code to a common ancestor, calling the inherited Create has the following advantages:
If the common ancestor has a constructor, you can't forget to call it.
If the common ancestor has a constructor with different parameters, the compiler warns you for this.
You can also override "procedure AfterConstruction". This procedure is always called, no matter what kind of constructor.
public
procedure AfterConstruction; override;
end;
procedure TfrmListBase.AfterConstruction;
begin
inherited;
//your stuff, always initialized, no matter what kind of constructor!
end;
For example: if you want to create an object with a different constructor than the normal TObject.Create, such as TComponent.Create(AOwner) or a custom (overloaded) constructor, you can get problems because your override is not called and (in this case) your "VectorNames" variable will be nil.
I call it, except when i need a very optimized constructor.

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