What is the difference with these two sets of code [closed] - delphi

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
What is the difference between these two pieces of code
type
IInterface1 = interface
procedure Proc1;
end;
IInterface2 = interface
procedure Proc2;
end;
TMyClass = class(TInterfacedObject, IInterface1, IInterface2)
protected
procedure Proc1;
procedure Proc2;
end;
And the following :
type
IInterface1 = interface
procedure Proc1;
end;
IInterface2 = interface(Interface1)
procedure Proc2;
end;
TMyClass = class(TInterfacedObject, IInterface2)
protected
procedure Proc1;
procedure Proc2;
end;
If they are one and the same, are there any advantages, or readability issues with either.
I guess the second means you cannot write a class that implements IInterface2 without implementing IInterface1, whilst with the first you can.

The two snippets of code have very different effects, and are in almost no way equivalent, if we are talking about Delphi for Win32 (Delphi for .NET has different rules).
A class that implements its interface must implement all the members of that interface's ancestors, but it does not implicitly implement the ancestors. Thus, attempts to assign instances of type TMyClass to locations of type IInterface1 will fail for the second case.
Related to the previous point, if IInterface1 and IInterface2 both had GUIDs, dynamic casts (using Supports or 'as') of interface references with a target type of IInterface1 would fail on instances of TMyClass in the second case.
The interface IInterface2 has an extra method in the second case, which it does not in the first.
Values of type IInterface2 in the second case are assignable to locations of type IInterface1; this is not true for the first case.
See for yourself in this example:
type
A_I1 = interface
end;
A_I2 = interface(A_I1)
end;
A_Class = class(TInterfacedObject, A_I2)
end;
procedure TestA;
var
a: A_Class;
x: A_I1;
begin
a := A_Class.Create;
x := a; // fails!
end;
type
B_I1 = interface
end;
B_I2 = interface
end;
B_Class = class(TInterfacedObject, B_I1, B_I2)
end;
procedure TestB;
var
a: B_Class;
x: B_I1;
begin
a := B_Class.Create;
x := a; // succeeds!
end;
begin
TestA;
TestB;
end.

First off, I'm assuming that the second example's declaration for IInterface2 is a typo and should be
IInterface2 = interface(Interface1)
because inheriting from itself is nonsensical (even if the compiler accepted it).
And "inheriting" is the key word there for answering your question. In example 1 the two interfaces are completely independent and you can implement one, the other, or both without problems. In example 2, you are correct that you can't implement interface2 without also implementing interface1, but the reason why that's so is because it makes interface1 a part of interface2.
The difference, then, is primarily structural and organizational, not just readability.

Assuming you meant
...
IInterface2 = interface(Interface1)
...
I interpret it the same as you, the second form requires a class implementing Interface2 to implement Interface1 as well, while the first form does not.

I guess the second means you cannot write a class that implements IInterface2 without implementing IInterface1, whilst with the first you can.
That would be the technical difference.
Which one is better depends very much on what the interfaces actually are. Does it ever make sense for an IInterface2 to exist without it also being an IInterface1?
If IInterface1 is "displayable" and IInterface2 is "storable," then the first option probably makes more sense. If IInterface1 is "vehicle" and IInterface2 is "truck," then the second option probably makes much more sense.

Related

Delphi interfaces and IList<T> (or TObjectList<T>)

I'm trying to implement Spring 4 Delphi and only program to interfaces instead of classes. However this seems impossible when you want to use a TObjectList.
Consider the following code:
unit Unit1;
interface
uses
Spring.Collections,
Spring.Collections.Lists;
type
IMyObjParent = interface
['{E063AD44-B7F1-443C-B9FE-AEB7395B39DE}']
procedure ParentDoSomething;
end;
IMyObjChild = interface(IMyObjParent)
['{E063AD44-B7F1-443C-B9FE-AEB7395B39DE}']
procedure ChildDoSomething;
end;
implementation
type
TMyObjChild = class(TInterfacedObject, IMyObjChild)
protected
procedure ParentDoSomething;
public
procedure ChildDoSomething;
end;
{ TMyObj }
procedure TMyObjChild.ChildDoSomething;
begin
end;
procedure TMyObjChild.ParentDoSomething;
begin
end;
procedure TestIt;
var
LMyList: IList<IMyObjChild>;
begin
TCollections.CreateObjectList<IMyObjChild>;
//[DCC Error] Unit1.pas(53): E2511 Type parameter 'T' must be a class type
end;
end.
I know I can change IMyObjChild to TMyObjChild in the example above, but if I need that in another unit or a form then how do I do this?
Trying to program only to interfaces seems too hard or impossible as soon as you need a TObjectList.
Grrr... Any ideas or help?
CreateObjectList has a generic constraint that its type parameter is a class:
function CreateObjectList<T: class>(...): IList<T>;
Your type parameter does not meet that constraint since it is an interface. The thing about an object list is that it holds objects. If you take a look at TObjectList in Spring.Collections.Lists you'll see that it also has the generic constraint that its type parameter is a class. And since CreateObjectList is going to create a TObjectList<T>, it must reflect the type constraint.
The raison d'ĂȘtre of TObjectList<T> is to assume ownership of its members through the OwnsObjects. Much in the same way as do the classic Delphi RTL classes of the same name. Of course you are holding interfaces and so you simply do not need this functionality. You should call CreateList instead. A plain TList<T> is what you need, even if you refer to it through the IList<T> interface.
LMyList := TCollections.CreateList<IMyObjChild>;

Delphi generics: How to spec "class that references its own type"

In Delphi XE2, I want to write a generic collection class which manipulates objects which must have a Copy(owntype) method, but I can't figure out how best to declare this.
I want something like this example (a collection of one item, for simplicity):
//------ Library ------
Type
TBaseCopyable = class
S: string;
// procedure Copy(OtherObject: TBaseCopyable); overload;
procedure Copy(OtherObject: TBaseCopyable); virtual;
end;
MyCollection<T: TBaseCopyable, constructor> = class
TheItem: T;
procedure SetItem(AItem: T);
function GetItem: T;
end;
[...]
function MyCollection<T>.GetItem: T;
Var
NewItem: T;
begin
NewItem := T.Create;
NewItem.Copy(TheItem);
Result := NewItem;
end;
//------ Usage ------
Type
TMyCopyable = class(TBaseCopyable)
I: integer;
// procedure Copy(OtherObject: TMyCopyable); overload;
procedure Copy(OtherObject: TMyCopyable); override;
end;
[...]
Col: MyCollection<TMyCopyable>;
The key problem is that in Col, I need the generic implementation of MyCollection to find TMyCopyable.Copy. Unsurprisingly, neither overload or virtual do the job:
With overload, the code compiles, but MyCollection.GetItem finds
TBaseCopyable.Copy, not TMyCopyable.Copy.
With virtual/override this
doesn't compile because the signatures of the two Copy declarations
don't match.
So I figure I need to use generics somehow in the specification of TBaseCopyable, possibly instead of inheritance. But I'm not sure how, primarily because I don't particularly need to feed a type parameter into TBaseCopyable, I just need the Copy argument type to refer to "the type of it's own class" in a generic way.
Ideas? Thanks!
Turn TBaseCopyable into a Generic class and apply its Generic type to Copy(), then TMyCopyable can override it, eg:
type
TBaseCopyable<T> = class
S: string;
procedure Copy(OtherObject: T); virtual;
end;
MyCollection<T: TBaseCopyable<T>, constructor> = class
TheItem: T;
procedure SetItem(AItem: T);
function GetItem: T;
end;
type
TMyCopyable = class(TBaseCopyable<TMyCopyable>)
I: integer;
procedure Copy(OtherObject: TMyCopyable); override;
end;
Alternatively, just do the same thing that TPersistent.Assign() does (since it does not use Generics):
type
TBaseCopyable = class
S: string;
procedure Copy(OtherObject: TBaseCopyable); virtual;
end;
MyCollection<T: TBaseCopyable, constructor> = class
TheItem: T;
procedure SetItem(AItem: T);
function GetItem: T;
end;
type
TMyCopyable = class(TBaseCopyable)
I: integer;
procedure Copy(OtherObject: TBaseCopyable); override;
end;
procedure TMyCopyable.Copy(OtherObject: TBaseCopyable);
begin
inherited;
if OtherObject is TMyCopyable then
I := TMyCopyable(OtherObject).I;
end;
Answering my own question, or at least summarizing findings:
So far as I can tell, there is no complete answer to the question as I posed it. What I have learned is this:
[1] Remy's solution is the way to go if the base item class (here TBaseCopyable) has no state, and either is abstract, or methods don't need to refer to other objects of the same type. (Eg: TBaseCopyable would have no fields and only abstract methods.)
[2] A significant issue is how to specify a generic class whose descendant classes can specify method arguments and return values of the same type as their enclosing class. In Remy's example, that is accomplished in the descendant class declaration:
TMyCopyable = class(TBaseCopyable<TMyCopyable>)
This means that in the generic class, T will be replaced by the ultimate class of interest.
[3] However, within TBaseCopyable's generic declaration, the information that T is always a TBaseCopyable is not available, so in TBaseCopyable's implementation, references to objects of type T won't be able to see TBaseCopyable's methods or fields.
This would be solved if we could set a constraint on T to tell the compiler that T is a TBaseCopyable.
That's apparently the approach in C#:
http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx
In Delphi, I think that would go like this:
type
TBaseCopyable<T: TBaseCopyable<T> > = class
...
like Remy shows for MyCollection. However, that syntax is not legal within the same class declaration (error: undeclared identifier TBaseCopyable), because TBaseCopyable is not yet fully defined. We might think to create a forward declaration for TBaseCopyable (like we would for non-generic classes), but that throws an error, and apparently it's not supported by the compiler:
How to set a forward declaration with generic types under Delphi 2010?
E2086 error with forward declaration of a generic type http://qc.embarcadero.com/wc/qcmain.aspx?d=94044
[4] Maybe the generic class could inherit the implementation?
What if we did this:
type
TBaseCopyable<T> = class(TBaseCopyableImpl) ...
That would allow TBaseCopyable to have some fields and methods that could refer to each other. However, even if those methods were virtual, they would impose fixed argument/return types on the descendants, the avoidance of which was the rationale for using generics in the first place.
So this strategy is only good for fields and methods that don't need to specialize in the descendant types... for example an object counter.
Conclusions
This question turns out to concern the somewhat-known "Curiously recurring template pattern": http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern. Even though it seems what one is trying to accomplish is simple, there are theoretical problems behind the scenes.
The situation appears to call for a language keyword meaning something like "Same type as my enclosing class". However that apparently leads to covariance/contravariance issues -- violations of the rules of which types can substitute for which in inheritance hierachies. That said, it seems Delphi doesn't go as far as C# to permit as much of a partial solution.
Of course, I'd be happy to learn that there is a way to go further!
Oh, and I don't feel too bad struggling to get to the bottom of this -- even Ken Arnold thinks it's difficult: https://weblogs.java.net/blog/arnold/archive/2005/06/generics_consid.html#comment-828994
:-)

Inheriting from generic's parameter doesn't work in Delphi XE

I've been trying to extend a bunch of library classes inheriting from the same base class by overriding a virtual method defined in that base class. The modification is always the same so instead of creating N successors of the library classes I decided to create a generic class parameterized by the library class type, which inherits from the class specified by parameter and overrides the base class' method.
The problem is that the code below doesn't compile, the compiler doesn't allow inheriting from T:
program Project1;
type
LibraryBaseClass = class
procedure foo; virtual;
end;
LibraryClassA = class(LibraryBaseClass)
end;
LibraryClassB = class(LibraryBaseClass)
end;
LibraryClassC = class(LibraryBaseClass)
end;
LibraryClassD = class(LibraryBaseClass)
end;
MyClass<T:LibraryBaseClass> = class(T) //Project1.dpr(20) Error: E2021 Class type required
procedure foo; override;
end;
procedure LibraryBaseClass.foo;
begin
end;
procedure MyClass<T>.foo;
begin
end;
begin
MyClass<LibraryClassA>.Create.foo;
MyClass<LibraryClassB>.Create.foo;
MyClass<LibraryClassC>.Create.foo;
MyClass<LibraryClassD>.Create.foo;
end.
Any ideas how to make this work? Maybe there is a way to trick the compiler into accepting something equivalent because, for example, inheriting from Dictionary<T,T> compiles without problems.
Or what would you do if you had the same goal as I? Keep in mind that in the real situation I need to override more than one method and add some data members.
Thank you
As you've been told already, this is valid with C++ templates, not with C# or Delphi generics. The fundamental difference between templates and generics is that conceptually, each template instantiation is a completely separately compiled type. Generics are compiled once, for all possible types. That simply is not possible when deriving from a type parameter, because you could get constructs such as
type
LibraryBaseClass = class
procedure foo; virtual;
end;
LibraryClassA = class(LibraryBaseClass)
procedure foo; reintroduce; virtual;
end;
LibraryClassB = class(LibraryBaseClass)
end;
MyClass<T:LibraryBaseClass> = class(T)
procedure foo; override; // overrides LibraryClass.foo or LibraryClassA.foo ?
end;
Yet this can work in C++, because in C++ MyClass<LibraryClassA> and MyClass<LibraryClassB> are completely separated, and when instantiating MyClass<LibraryClassA>, foo is looked up and found in LibraryClassA before the base class method is found.
Or what would you do if you had the same goal as I? Keep in mind that in the real situation I need to override more than one method and add some data members.
It is possible to create types at runtime, but almost certainly an extremely bad idea. I have had to make use of that once and would have loved to avoid it. It involves reading the VMT, creating a copy of it, storing a copy of the original LibraryBaseClass.foo method pointer somewhere, modifying the VMT to point to a custom method, and from that overriding function, invoking the original stored method pointer. There's certainly no built-in language support for it, and there's no way to refer to your derived type from your code.
I've had a later need for this in C# once, too, but in that case I was lucky that there were only four possible base classes. I ended up manually creating four separate derived classes, implementing the methods four times, and using a lookup structure (Dictionary<,>) to map the correct base class to the correct derived class.
Note that there is a trick for a specific case that doesn't apply to your question, but may help other readers: if your derived classes must all implement the same interface, and requires no new data members or function overrides, you can avoid writing the implementation multiple times:
type
IMySpecialInterface = interface
procedure ShowName;
end;
TMySpecialInterfaceHelper = class helper for TComponent
procedure ShowName;
end;
procedure TMySpecialInterfaceHelper.ShowName;
begin
ShowMessage(Name);
end;
type
TLabelWithShowName = class(TLabel, IMySpecialInterface);
TButtonWithShowName = class(TButton, IMySpecialInterface);
In that case, the class helper method implementation will be a valid implementation for the interface method.
In Delphi XE and higher, you could also try something completely different: TVirtualMethodInterceptor.
What you are attempting to do is simply not possible with Delphi generics.
For what it is worth, the equivalent code is also invalid in C# generics. However, your design would work with C++ templates.
I probably misunderstood your description of the problem but from your simplified example it seems you could "turn it around" and insert a class in the hierarchy in the middle like this:
program Project1;
type
LibraryBaseClass = class
procedure foo; virtual;
end;
LibraryBaseFooClass = class(LibraryBaseClass)
procedure foo; override;
end;
LibraryClassA = class(LibraryBaseFooClass)
end;
LibraryClassB = class(LibraryBaseFooClass)
end;
LibraryClassC = class(LibraryBaseFooClass)
end;
LibraryClassD = class(LibraryBaseFooClass)
end;
procedure LibraryBaseClass.foo;
begin
end;
procedure LibraryBaseFooClass.foo;
begin
end;
begin
LibraryClassA.Create.foo;
LibraryClassB.Create.foo;
LibraryClassC.Create.foo;
LibraryClassD.Create.foo;
end.

Casting a delphi interface to its implementation class without modifying the interface [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to cast a Interface to a Object in Delphi
Using Delphi 5; I have an interface that I cannot change for legacy reasons. I am passing (pointers to) that interface all over the place. The implementing class has several new properties - is there a way to force a cast from the interface to the actual implementation?
http://www.malcolmgroves.com/blog/?p=500 says that this is (newly) implemented in Delphi 2010, which strongly suggest that it wasn't possible before. Is this indeed the case, or is there a way I'm not familiar with? RTTI, maybe?
(I checked, and if pScore is TOleScore then is indeed not allowed by the Delphi 5 compiler - here pScore is my pScore: IScore argument, and TOleScore is the implementing class.)
The classic take on this is by Hallvard Vassbotn: Hack #7: Interface to Object
More recently Barry Kelly, a Delphi compiler engineer, also provided an implementation: An ugly alternative to interface to object casting
I think both approaches should work.
Incidentally, does anyone know if Hallvard is still active? I've not come across him in the past few years.
H/t to my boss, the answer is: use the incredibly useful JEDI library, specifically the GetImplementorOfInterface method.
i do what the "possible duplicate" question's accepted answer does:
Have the object implement the IObject interface:
IObject = interface(IUnknown)
['{39B4F98D-5CAC-42C5-AF8D-0237C8EFBE4C}']
function GetSelf: TObject;
end;
So it would be:
var
thingy: IThingy;
o: TOriginalThingy;
begin
o := (thingy as IObject).GetSelf as TOriginalThingy;
Update: To drive the point home, you can add a new interface to an existing object.
Existing object:
type
TOriginalThingy = class(TInterfacedObject, IThingy)
public
//IThingy
procedure DrinkCokeZero; safecall;
procedure ExcreteCokeZero; cafecall;
end;
Add IObject as one of the interfaces it exposes:
type
TOriginalThingy = class(TInterfacedObject, IThingy, IObject)
public
//IThingy
procedure DrinkCokeZero; safecall;
procedure ExcreteCokeZero; cafecall;
//IObject - provides a sneaky way to get the object implementing the interface
function GetSelf: TObject;
end;
function TOriginalThingy.GetSelf: TObject;
begin
Result := Self;
end;
Typical usage:
procedure DiddleMyThingy(Thingy: IThingy);
var
o: TThingy;
begin
o := (Thingy as IObject).GetSelf as TThingy;
o.Diddle;
end;

Are GUIDs necessary to use interfaces in Delphi?

The official documentation says they are optional. I know COM interop requires a unique identifier for each interface but every interface example I see has a GUID whether it's used with COM or not? Is there any benefit to including a GUID if its not going to be used with COM?
I've noticed that some methods such as Supports (to determine if a class conforms to a specific interface) require that you define a GUID before you can use them.
This page confirms it with the following information:
Note: The SysUtils unit provides an
overloaded function called Supports
that returns true or false when class
types and instances support a
particular interface represented by a
GUID. The Supports function is used in
the manner of the Delphi is and as
operators. The significant difference
is that the Supports function can take
as the right operand either a GUID or
an interface type associated with a
GUID, whereas is and as take the name
of a type. For more information about
is and as, see Class References.
Here's some interesting information about interfaces, which states:
Why does an interface need to be
uniquely identifiable? The answer is
simple: because Delphi classes can
implement multiple interfaces. When an
application is running, there has to
be a mechanism that will get pointer
to an appropriate interface from an
implementation. The only way to find
out if an object implements an
interface and to get a pointer to
implementation of that interface is
through GUIDs.
Emphasis added in both quotes.
Reading this entire article also makes you realize that QueryInterface (which requires a GUID) is used behind the scenes for reasons such as reference counting.
Only if you need your interface to be compatible with COM.
Unfortunately, that also includes using is, as operators and QueryInterface, Supports functions - the lack of which is rather limiting. So, while not strictly required, it's probably easier to use a GUID. Otherwise, you are left with rather simplistic usage only:
type
ITest = interface
procedure Test;
end;
ITest2 = interface(ITest)
procedure Test2;
end;
TTest = class(TInterfacedObject, ITest, ITest2)
public
procedure Test;
procedure Test2;
end;
procedure TTest.Test;
begin
Writeln('Test');
end;
procedure TTest.Test2;
begin
Writeln('Test2');
end;
procedure DoTest(const Test: ITest);
begin
Test.Test;
end;
procedure DoTest2(const Test: ITest2);
begin
Test.Test;
Test.Test2;
end;
procedure Main;
var
Test: ITest;
Test2: ITest2;
begin
Test := TTest.Create;
DoTest(Test);
Test := nil;
Test2 := TTest.Create;
DoTest(Test2);
DoTest2(Test2);
end;

Resources