Assigning interface pointers in a Delphi 6 class declaration? - delphi

Despite years of Delphi programming I just ran into a class declaration style I had never seen for a class that supports IUnknown:
TBCUnknown = class(TBCBaseObject, IUnKnown)
private
FRefCount: integer;
FOwner : Pointer;
protected
function IUnknown.QueryInterface = NonDelegatingQueryInterface;
function IUnknown._AddRef = NonDelegatingAddRef;
function IUnknown._Release = NonDelegatingRelease;
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
...
As you can see, assignments of class methods to IUnknown interface methods are being done right in the class declaration. This looks really strange to me especially since I don't see how the IUnknown methods could be assigned to, before the constructor is called. Is this some kind of compile-time shortcut for making assignments between a class's methods and the interface pointers for an interface the class accepts, that are later resolved at run-time? If someone could provide a little information on how this works and what Delphi idiom supports this kind of construct I'd like to know.

It's called Method Resolution Clause and it allows you to specify which method actually implements the specified interface method. This means that the implementing method can have a different name than the method declared in the interface (but the method signature still has to match). Without the clause, Delphi automatically resolves the implementation methods based on their names.
In your example, the declaration means that IUnknown._AddRef is implemented by TBCUnknown.NonDelegatingAddRef and IUnknown._Release by TBCUnknown.NonDelegatingRelease.
As far as I know, this has been supported from the beginning when interface support was added to the language. You probably haven't noticed it because it's not used or needed so often.

This is what is known as a Method Resolution Clause. To quote from the documentation:
You can override the default name-based mappings by including method resolution clauses in a class declaration. When a class implements two or more interfaces that have identically named methods, use method resolution clauses to resolve the naming conflicts.

Related

Why static is needed in the one case and is not mandatory in another one?

FreePascal, Delphi mode. After some experiments I found that this code is compiled, FPC says me that class procedure must be "static". But my question is: then why operator Equal does not need "static" and it's compiling fine?! Also I can not understand what is the difference to have "class" procedure and "class" with "static" (for example, in Python in classmethod you get argument - reference to the class, in staticmethod - you have not such argument).
type TPos = record
FLine: Word;
FPos: Word;
class procedure Init(out a: TPos); static;
class operator Equal(a, b: TPos): Boolean;
end;
PS. I set "delphi" tag because: 1) it's written in delphi mode 2) because I found the same documentation for Delphi: about class and static keywords.
Contrary to what you state, a non-static class method does have a reference to the class passed as an argument. It's an implicit argument named Self.
For class methods on records as opposed to classes, since there is no inheritance, this Self parameter would serve no purpose, and so it is never passed. Hence all class methods on records must be static.
A class operator is implicitly a static method and so you don't need to state that. In other words, operator implies static.

Can I make the compiler fail if Create is called explicitly?

I have many singletons where I don't want the developers to call the constructor Create. Instead they should use the function Instance
TdgpBankBranch = class(TDataGroup)
strict private
class var InstanceVar : TdgpBankBranch;
private
{ Only for internal use }
constructor Create (AOwner : TComponent); reintroduce;
protected
public
class function Instance : TdgpBankBranch;
class function Is_A_Live_Singleton: boolean;
property Rec[Bank, Branch : integer]: TBankBranch read GetRec; default;
end;
I have been shifting the constructors to private. This makes the code analysers complain "Non-public constructor".
I could shift them back to public. Is there a way to make the compiler fail if an attempt is made at using the constructor ?
Moving the constructor to private will prevent other units from being able to call Create() directly, however code inside the same unit as the class will still be able to call it unhindered, due to implicit friendship within a unit. If you don't want any code outside of the class calling Create() directly, even in the same unit, then declare it as strict private so only the class itself can call it directly.
You ask how to stop the compiler from creating an object when somebody calls .create, but what you're trying to do is create a singleton, so it helps to see how others solved this.
In Delphi, singletons are often implemented via a function that's declared in the interface section and which returns an object that's declared in the implementation section of a unit. The function creates the instance if it doesn't exist yet, to provide lazy loading. Cleanup is done via the finalization section.
In your situation, instead of having an instance() function, you just create a global function that gives you an instance.
This approach probably stems from the days before classes and private sections existed, but it's pretty straightforward, and prevents the issue that you're running in to. Look at how TClipboard is implemented. This implementation is not possible in Java or C# because they don't have global functions, or the type of scoping that makes this Delphi implementation work...
Or take a look at this answer by David Heffernan:
Delphi Singleton Pattern
It's even better than TClipboard, because it hides the entire class in the implementation section, truly preventing people to create instances themselves, but you'll have to create an interface for your class.

Delphi - Interfaces and overload directive

I'm a little bit confused on interfaces in Delphi, so I'm asking you about this. An interface can be 'associated' with an abstract class. (It does not implement the methods declared on it.) All the methods declared on it are implemented in the class/classes which is/are implementing the interface.
So, why then is it allowed to have the overload directive on the method declaration of an interface?
type
IFoo = interface
function Test : String; overload;
end;
Compiler is quiet on this.
overloaded allows to have few the same named methods, but with different parameter sets, in a single class / interface.
Your interface has Test method. With this single method there is no need for overloaded. But you can introduce, if you need, additional Test methods with differrent parameter sets.
Probably you are thinking about override directive ...

Can a Delphi generic class descend from its class argument?

I've been trying to define a generic, inheritable TSingleton class. Here's what I had in progress:
TSingleton<RealClass, InheritsFrom : class> = class(InheritsFrom)
strict private
class var FInstance : RealClass;
protected
procedure InstanceInitialization;virtual;
public
destructor Destroy; override;
class procedure Create; reintroduce;
class function Instance : RealClass;
class procedure InstanceFree;
end;
The goal was to be able to "insert" the singleton pattern in an inheritance tree. so instead of declaring something like this :
TMySingletonComponent = class(TComponent)
end;
And need to implement the singleton pattern there, I would declare something like this :
TMyGenericSingletonComponent = class(TSingleton<TMyGenericSingletonComponent,TComponent>)
end;
Sadly, this won't work. I'm getting the following error(In D2010):
TSingleton<RealClass, InheritsFrom : class> = class(InheritsFrom) ///E2021 Class type required
Now I was wondering, would this work in Delphi XE? Is there some "clean hack" I could use to make this work in D2010? Is there some fundamental reasons why this can't work?
By design, you can't create a generic class which derives from one of its type arguments.
No, that won't work. You're trying to define a class in terms of itself. Whatever you put inside the parameters has to be fully defined already.
What do you want to obtain?
IMHO, singletons are evil. They were introduced because of bad OOP design of C++ (for access to input/output streams in console applications, as far as I remember). And they tend to be like hell to maintain.
You can always live without them. It's definitively not a "Delphi classical" way of programing, because Delphi doesn't suffer the C++ problems I mentioned.
Some Java project (ab)uses of singleton. Google for it, and you'll find out what I mean.
Use a property of a common class with a getter, initializing an instance if the corresponding field is still nil, or directly returning the field pointer to the instance if it was already created. You'll have the singleton feature, with good performance, nice code, good OOP practice (no "global" class), and the ability to run the class without any singleton feature, if you don't need this feature later (for testing purpose, for instance).

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