#1 Re: Language » Save object, stop class hegemony! » 2024-05-08 08:30:30

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;

#2 Re: mORMot 2 » Compiling Project02Server example on Delphi 11 » 2023-07-28 09:29:04

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>

#3 mORMot 2 » Compiling Project02Server example on Delphi 11 » 2023-07-27 12:16:32

malom
Replies: 2

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.

#4 Re: mORMot 1 » Automatic TSQLRecord memory handling » 2018-10-18 11:57:13

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;

Board footer

Powered by FluxBB