You are not logged in.
Pages: 1
Somewhat related to this topic, and confirms, that old style TP "object" could be very useful, and should not be deprecated. Some time ago I found, that "object"s do support interfaces, at least at syntax level. I posted it as a comment, but I think, only Mr. Pluimers have read it:
https://wiert.me/2014/02/20/hidden-feat … these-too/
Look at the declarations here. The implementation is in the blog comment...That is poor and not very interesting.
type
TInterfacedBase = object // Not CLASS
private
FInterfaceTable: Pointer;
FRefCount: Integer;
public
constructor Init;
destructor Done;
function GetInterface: IInterface;
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;
ITest = interface
function Foo: string;
end;
// TTest = object(ITest) // Must have an ancestor OBJECT type or gives a syntax error
TTest = object(TInterfacedBase, ITest)
public
constructor Init;
function Foo: string;
end;
Sorry. Don't waste your valuable time with it.
It seems to me unrelated to Mormot, it is a reproducible IDE bug:
When opening "Project02Server.dpr", a "Project02Server.dproj" file is automatically generated by the IDE,
and it contains a specific line that contains "mormot.core".
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;mormot.core;$(DCC_Namespace)</DCC_Namespace>
<PropertyGroup Condition="'$(Base)'!=''">
<DCC_E>false</DCC_E>
<DCC_F>false</DCC_F>
<DCC_K>false</DCC_K>
<DCC_N>false</DCC_N>
<DCC_S>false</DCC_S>
<DCC_ImageBase>00400000</DCC_ImageBase>
<SanitizedProjectName>Project02Server</SanitizedProjectName>
<VerInfo_Locale>1038</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=</VerInfo_Keys>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;mormot.core;$(DCC_Namespace)</DCC_Namespace>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
</PropertyGroup>
Compilation fails with error message: "[dcc32 Fatal Error] mormot.core.variants.pas(27): F2047 Circular unit reference to 'mormot.core.base'".
I found, that it is caused by the "Unit scope names" project option: "System;Xml;Data;Datasnap;Web;Soap;mormot.core".
After deleting "mormot.core", it compiles. I don't know why, so I reported the problem, but don't know wether it is a valid solution.
I played a lot with Your nice IAutoFree idea, and finally got to a different implementation, currently for test purposes, working only with a single object instance.
I really can't decide wether this is cool or fool, so I woudld be appreciated on any comment.
// TAutoFreeData - useful for simple classes that do not have constructor and destructor ie. for emulating pascal record behavior with property access syntax.
type
// Memory signature on the heap
PAutoFreeRec = ^TAutoFreeRec;
TAutoFreeRec = packed record
AutoFree: packed record
ClassType: TClass;
RefCount: Integer;
Unknown: {array[0..0] of} Pointer; // TODO: What is this? Actually initialized by TAutoFreeData.InitInstance().
end;
Instance: packed record
ClassType: TClass;
// Data: array[1..Instance.ClassType.InstanceSize - SizeOf(Instance.ClassType)] of Byte;
end;
end;
// Implements the reference counted interface
TAutoFreeData = class(TInterfacedObject)
public
destructor Destroy; override;
end;
// Just for accessing RefCount
TAutoFreeInfo = class
private
function getAutoFree: TAutoFreeData;
public
property AutoFree: TAutoFreeData read getAutoFree;
end;
destructor TAutoFreeData.Destroy;
begin
//* Cleanup aClassType instance
// MUST NOT call Instance.Destroy, since
// it is not directly allocated on the heap, and destructor finally calls System._FreeMem()
TObject(@PAutoFreeRec(Self)^.Instance).CleanupInstance;
//* Destroy AutoFree instance and Free allocated memory
inherited;
end;
function TAutoFreeInfo.getAutoFree: TAutoFreeData;
begin
Result := TAutoFreeData(@PAutoFreeRec(Integer(Self) - SizeOf(PAutoFreeRec(nil)^.AutoFree))^.AutoFree);
end;
function AutoFreeData(var aLocalVar; aClassType: TClass): IInterface;
var
Size: integer;
begin
//* Allocate space on heap for TAutoFreeData and aClassType instance
Size := TAutoFreeData.InstanceSize + aClassType.InstanceSize;
GetMem(Pointer(aLocalVar), Size);
//* Fill only Instance.Data with zeroes
// FillChar(Pointer(aLocalVar)^, Size, 0);
FillChar(PAutoFreeRec(Integer(aLocalVar) + SizeOf(TAutoFreeRec))^, Size - SizeOf(TAutoFreeRec), 0);
//* Initialize AutoFreeData instance and return interface reference
Result := TAutoFreeData(TAutoFreeData.InitInstance(TAutoFreeData(aLocalVar)));
//* Initialize aClass instance
//* Not necessary to call aClassType.InitInstance on constructorless simple classes
// aClassType.InitInstance(TObject(@PAutoFreeRec(aLocalVar)^.Instance));
PAutoFreeRec(aLocalVar)^.Instance.ClassType := aClassType;
//* Set aLocalVar
Pointer(aLocalVar) := @PAutoFreeRec(aLocalVar)^.Instance;
end;
type
// Not mandatory to inherit from TAutoFreeInfo. It is just for test.
TTestRec28C = class(TAutoFreeInfo)
private
fID: Integer;
fName: string;
published
property ID: Integer read fID write fID;
property Name: string read fName write fName;
end;
// Inheritance and virtual functions will work
TTestRec28VC = class(TTestRec28C)
function getCalculated: string; virtual;
published
property Calculated: string read getCalculated;
end;
function TTestRec28VC.getCalculated: string;
begin
Result := Format('ID: %d, Name: %s', [ID, Name]);
end;
procedure Test28;
var
d1, d2: IInterface;
c: TTestRec28C;
sl: TStringList;
procedure Log(const Fmt: string; const Params: array of const);
begin
sl.Add(Format(Fmt, Params));
end;
begin
sl := TStringList.Create;
d1 := AutoFreeData(c, TTestRec28VC);
Log('c.ClassName: %s', [c.ClassName]);
Log('c.AutoFree.ClassName: %s', [c.AutoFree.ClassName]);
Log('c.AutoFree.RefCount: %d', [c.AutoFree.RefCount]);
c.ID := 1;
c.Name := 'First';
Log('c.ID: %d', [c.ID]);
Log('c.Name: %s', [c.Name]);
Log('c.Calculated: %s', [(c as TTestRec28VC).Calculated]);
d2 := d1;
Log('c.AutoFree.RefCount: %d', [c.AutoFree.RefCount]);
sl.SaveToFile(IncludeTrailingPathDelimiter(ExtractFileDir(Application.ExeName)) + 'Test28.txt');
sl.Free;
end;
Pages: 1