Search the Community
Showing results for tags 'interface'.
Found 5 results
- I use Pascal Analyzer. It is a great application for detecting both small and large mistakes that can occur. Now I got WARN53. From doc at https://www.peganza.com/PALHelp/index.html?warnings_report.htm WARN53-Mixing interface variables and objects This section reports locations in your code with assignments between objects and interface variables. Normally, unless you really know what you are doing, it is a bad idea to mix interfaces and objects. The reason is that the reference counting mechanism of interfaces can be disturbed, leading to access violations and/or memory leaks. Example: My method. TBoldMember is a class in Bold for Delphi function TModificationHistoryTracker.GetOldLink(ABoldMember: TBoldMember): TBoldObject; var StringRepresentable: IBoldStringRepresentable; OldValue: IBoldValue; begin OldValue := ABoldMember.OldValue; if Assigned(OldValue) then begin if not Supports(OldValue, IBoldStringRepresentable, StringRepresentable) then raise EModificationHistoryTracker.Create('Unsupported value type.'); Result := GetApplicationKernel.MetaSystem.GetObjectForIdString(StringRepresentable.asString); end else Result := nil; end; I also asked Claude, and it claimed that this could be a problem, as both Bold may free the memory. When OldValue goes out of scope, the reference becomes 0, and another free operation occurs. So the same memory is freed twice. The solution would be to remove the temporary variable OldValue. I have to say that I am confused. Is the code OK or bad? Here is the text from Claude: The Core Issue: Two Different Memory Management Models Delphi has two fundamentally different ways of managing object lifetime, and your code is mixing them in a way that can be dangerous. Object references use manual memory management. When you create an object with TMyObject.Create, you own that object and must explicitly call Free to destroy it. The object exists until you explicitly destroy it, regardless of how many variables point to it. Interface references use automatic reference counting. When you assign an object to an interface variable, Delphi automatically tracks how many interface variables are pointing to that object. When the last interface reference goes out of scope, Delphi automatically destroys the object. What's Happening in Your Code Let's trace through your code step by step: OldValue := ABoldMember.OldValue; The property ABoldMember.OldValue is declared as returning IBoldValue, which is an interface type. However, internally, the Bold framework is managing actual objects (probably instances of TBoldValue or a descendant class). These objects are owned and managed by the Bold framework itself using its own lifecycle management. When you assign this to your OldValue variable, something subtle but important happens. Delphi performs an implicit cast from the object to the interface. This cast does several things behind the scenes: First, Delphi calls QueryInterface on the underlying object to get the IBoldValue interface pointer. Second, and this is the critical part, Delphi increments the reference count on that object. The object now thinks it has one interface reference pointing to it. Why This Creates a Problem The Bold framework created and owns that TBoldValue object. It's managing that object's lifetime as part of its domain model. The framework expects to be in control of when that object lives and dies. But now you've created an interface reference to it. When your OldValue variable goes out of scope at the end of the function, Delphi will automatically decrement the reference count. If that reference count reaches zero, Delphi will attempt to destroy the object. This creates a conflict. You have two different systems trying to manage the same object's lifetime. The Bold framework thinks it owns the object and will free it when appropriate. The interface reference counting system also thinks it has responsibility for the object. This can lead to several problems: The object might be destroyed prematurely while Bold still needs it, causing access violations later. Alternatively, if Bold manages to free the object first, your interface reference becomes a dangling pointer, and when it goes out of scope, Delphi tries to decrement the reference count on an already-freed object, causing a crash. In some cases, you might get a memory leak if the reference counting prevents Bold from properly cleaning up. Why Pascal Analyzer Warns Pascal Analyzer performs static analysis on your code. It sees that you're taking a property that returns an interface type and storing it in a local interface variable. It recognizes this pattern as potentially dangerous because it's mixing two incompatible memory management strategies. The analyzer is essentially saying: "I see you're creating a reference-counted interface reference to an object that might be managed by a different system. This could cause lifetime management conflicts." The Solution The way to fix this is to avoid creating the intermediate interface variable. Instead, use the property directly where you need it. This way, you're still working with the interface, but you're not creating a stored reference that participates in reference counting:
- Hello Guys, good afternoon, it's still 4:25 pm where I live, I already know a lot about Delphi related to OOP, but I have one subject that I still have doubts about, which is the interface issue. My questions would be, when should I use an interface? To create my interface factory, should I create just the factory class or the class and a factory interface as well? How should I develop this knowledge and understand this concept once and for all.
-
Compile time issue with RTTI, generic interface and type casting...
Ali Dehban posted a topic in RTL and Delphi Object Pascal
Hi mates, I have something on my mind but I couldn't implement it correctly, imagine a generic interface, some classes inherited from that interface, and one method in each class with the same name, now I'm trying to use this interface type every where for different approaches but it doesn't compile correctly. Please have a look at the code if you get a chance and share your thoughts with me, I do appreciate you in advance. The question is how can I implement such an idea properly and safely? I have attached a sample project to save you time too. unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Rtti; type IMyInterface<T> = interface function DoSomething: T; end; TMyClass<T> = class(TInterfacedObject, IMyInterface<T>) function DoSomething: T; end; TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private { Private declarations } function UseInterface<T>(obj: IMyInterface<T>): T; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} { TMyClass<T> } function TMyClass<T>.DoSomething: T; var ctx: TRttiContext; typ: TRttiType; begin ctx := TRttiContext.Create; typ := ctx.GetType(TypeInfo(T)); if typ.TypeKind = tkInteger then Result := 20 // E2010 Incompatible types: 'T' and 'Integer' else if typ.TypeKind = tkString then Result := T('Hello') // E2089 Invalid typecast else if typ.AsInstance.MetaclassType.InheritsFrom(TStringList) then Result := (typ.AsInstance.MetaclassType.InitInstance(typ) as TStringList) //E2010 Incompatible types: 'T' and 'TStringList' else Result := Default(T); ctx.Free; end; { TForm1 } function TForm1.UseInterface<T>(obj: IMyInterface<T>): T; begin Result := obj.DoSomething; end; procedure TForm1.FormCreate(Sender: TObject); var obj1: IMyInterface<Integer>; obj2: IMyInterface<String>; obj3: IMyInterface<TStringList>; begin try obj1 := TMyClass<Integer>.Create; obj2 := TMyClass<String>.Create; obj3 := TMyClass<TStringList>.Create; ShowMessage(UseInterface<Integer>(obj1).ToString); ShowMessage(UseInterface<String>(obj2)); ShowMessage(UseInterface<TStringList>(obj3).Text); except on E: Exception do Writeln('Exception: ', E.ClassName, ': ', E.Message); end; end; end. Generic Interface.zip -
I got bitten by an interface!
Clément posted a topic in Algorithms, Data Structures and Class Design
Hi, I'm experimenting some interface design and came up with the following: I would like to query a BaseClass instance if it supports a given interface, without freeing the class! As the example below, my great grand child class can support an interface, but I don't want to include the class definition ( great grand child class ) in the Base class.. So, by defining interfaces, I can write exactly what I want: TMyFrame = Class( TBaseFrame, {SupportedInterfaces}) In the code below procedure TForm22.Button1Click(Sender: TObject); begin if Supports( fBaseFrameClass, ISupportTask ) then (fBaseFrame as ISupportTask).CheckTask; end; No matter what overload Support method I call, fBaseFrame is freed once the method exits. Is there a way to know if my class instance supports an interface and call the corresponding method without messing ref counting and free the class instance prematurely? unit frm.main; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type ISupportTask = Interface ['{3F785F20-7C44-4163-B55C-5EA267C7204E}'] function CheckTask : Boolean; end; ISupportList = Interface ['{9B7D95E1-DA96-475A-9A1C-910CAF99E5F5}'] function ListCount : Integer; End; ISupportItem = Interface ['{ACADFA2F-3500-4ACB-8049-F49FAC38EFB2}'] function SaveItem : Boolean; End; TBaseFrame = Class( TInterfacedObject ) protected fDummy : Boolean; End; TBaseFrameClass = Class of TBaseFrame; TMyFrame = Class( TBaseFrame, ISupportTask, ISupportList, ISupportItem ) public function CheckTask : Boolean; function ListCount : Integer; function SaveItem : Boolean; destructor Destroy; override; End; TForm22 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } fBaseFrameClass : TBaseFrameClass; fBaseFrame : TBaseFrame; public { Public declarations } end; var Form22: TForm22; implementation {$R *.dfm} procedure TForm22.Button1Click(Sender: TObject); begin if Supports( fBaseFrameClass, ISupportTask ) then (fBaseFrame as ISupportTask).CheckTask; end; { TMyFrame } function TMyFrame.CheckTask: Boolean; begin Result := True; end; destructor TMyFrame.Destroy; begin fDummy := True; inherited; end; function TMyFrame.ListCount: Integer; begin Result := 42; end; function TMyFrame.SaveItem: Boolean; begin Result := False; end; procedure TForm22.FormCreate(Sender: TObject); begin fBaseFrameClass := TMyFrame; fBaseFrame := fBaseFrameClass.Create; end; procedure TForm22.FormDestroy(Sender: TObject); begin fBaseFrame.Free; end; end. - I want to get a list of interfaces registered in a Delphi 2007 application (with code from within that application) in order to check for possible duplicate GUIDs. There is a solution on GitHub which uses the System.RTTI unit, but unfortunately that unit is not available in Delphi 2007. Is it possible to do without? I also asked on StackOverflow: https://stackoverflow.com/q/54710667/49925
- 8 replies
-
- delphi-2007
- rtti
- (and 2 more)
Tagged with:
![Delphi-PRAXiS [en]](https://en.delphipraxis.net/uploads/monthly_2018_12/logo.png.be76d93fcd709295cb24de51900e5888.png)