[DUG] BDS.exe memory issues

Kyley Harris Kyley at harrissoftware.com
Thu Apr 16 19:32:01 NZST 2009


What I have done is no different than if you use a DFM or a modelmaker or
UML code generating type app. I am not metaprogramming at all.. (well not
much ) The main reason the files are humongoues, is because delphi does not
support Generics :D not my version anyway.. By using the code generator I
can happily bloat out the code with no sacrafice for time or effort and have
subclasses for every type and list that explicitly override each property to
return the correct managed class.

My current project manages nearly 500 objects.. about 1/2 correlate to
persisted data in a database, the rest are messaging layers over the
middletier.. The code generated (see sample) is about 1.2million lines of
code. with generics it would be about 100,000.
With 1 button push, the source code is generated, the database is created,
all stored procedures and triggers, etc etc are all built and I have an
application ready to run.. takes about 1 minute on a project of this size.
building 1.2million lines of source takes 3 seconds.

apart from the code generated managed objects, i doubt I have many units of
code > 15,000.

My Object database that uses SQL Server, or interbase as a back end is 4000
lines of code that handles all read/write of any data to the database and
management of the objects.

As to what is included in the 150,000 lines of code.. well.. I can tell you
that if delphi supported generics then that would probably be about 15,000
lines of code.. There is no wasted code in these lines of source.. no excess
fat.. its just what the classes require without cheating to save time :) I
don't need to save time.. it is built for me.
IT does not matter how many lines of code there are if they are maintained
without error.. if they do what they do efficiently and without errors or
memory leaks..

example of 1 such generated object. ( I will pick a small one)  Those lines
also tend to include comments and documentation..
For each object, I create a subclass of a list object, as well as a subclass
of an index.. these are purely so that I can access methods and return the
correct class from the method with overrides.. I could not do this, and have
less code and write (getItem as TBLas ) throughout my code.. but why would I
ruin my readability when I have a code generator..

(*  THIS IS JUST A PORTION OF AN INTERFACE SECTION *)
  TCLIENTBANK_CLIENTBANKID = 'ClientBankID';
  TCLIENTBANK_LASTMODIFIED = 'LastModified';
  TCLIENTBANK_CLIENTID = 'ClientID';
  TCLIENTBANK_BANKBRANCHID = 'BankBranchID';
  TCLIENTBANK_ACCOUNTNO = 'AccountNo';
  TCLIENTBANK_DRAWERNAME = 'DrawerName';


  TClientBank = class(TItem)
  private
    FClientBankID:TItemPrimaryKey;
    FLastModified:TDateTime;
    FClientID:TItemPrimaryKey;
    FBankBranchID:TItemPrimaryKey;
    FAccountNo:TSerialNumber;
    FDrawerName:string;
  protected
    procedure SetClientBankID(const Value:TItemPrimaryKey);
    function GetLastModified:TDateTime;
    procedure SetLastModified(const Value:TDateTime);
    procedure SetClientID(const Value:TItemPrimaryKey);
    procedure SetBankBranchID(const Value:TItemPrimaryKey);
    procedure SetAccountNo(const Value:TSerialNumber);
    procedure SetDrawerName(const Value:string);
  protected
    function GetDisplayName: string; override;
  public
    constructor Create(Items:TItems);override;
    destructor Destroy;override;
    class function TagName:string; override;
    class function PrimaryField:string;override;
    class function ObjectVersion:integer;override;
    function Clone(AOwner:TItems=nil):TClientBank;
  published
 { Auto Generated Field for the database }
    property ClientBankID:TItemPrimaryKey read FClientBankID write
SetClientBankID;
 { Auto Generated Field for the database }
    property LastModified:TDateTime read GetLastModified write
SetLastModified;
    property ClientID:TItemPrimaryKey read FClientID write SetClientID;
    property BankBranchID:TItemPrimaryKey read FBankBranchID write
SetBankBranchID;
    property AccountNo:TSerialNumber read FAccountNo write SetAccountNo;
    property DrawerName:string read FDrawerName write SetDrawerName;
  end;

  TClientBankIndex = class;
  TClientBanks = class(TItems)
  private
    function GetItem(Index: Integer): TClientBank;
    procedure SetItem(Index: Integer; const Value: TClientBank);
    function GetFirst:TClientBank;
    function GetLast:TClientBank;
    function GetNext(AItem: TItem): TClientBank;
    function GetPrevious(AItem: TItem): TClientBank;
  public
    class function GetItemClass:TItemClass;override;

    function DefaultIndexClass:TItemIndexClass;override;
    function
NewIndex(IndexName:string;IndexFields:string;FieldLookup:TFieldReplaceEvent=nil;ItemFilter:TItemFilterEvent=nil):TClientBankIndex;
    function GetIndex(IndexName:string):TClientBankIndex;

    function Add(AClass:TItemClass=nil): TClientBank;
    function Insert(Index: Integer): TClientBank;
    function GetItemByPrimaryKey(AKey:TItemPrimaryKey):TClientBank;
    property Items[Index: Integer]: TClientBank read GetItem write
SetItem;default;
    property First:TClientBank read GetFirst;
    property Last:TClientBank read GetLast;
    property Previous[AItem:TItem]:TClientBank read GetPrevious;
    property Next[AItem:TItem]:TClientBank read GetNext;
  end;

  TClientBankIndex = class(THsAvlItemNonUniqueIndex)
  protected
    function GetItem(index: integer): TClientBank;
    function GetFirst:TClientBank;
    function GetLast:TClientBank;
  public
    {@@ returns the ordinal position of the item in the index.}
    function PositionOfItem(AItem:TClientBank):integer;
    function IndexPositionOfItem(AItem:TClientBank):integer;
    {@@ find an item based on index data}
    function Find(Values:array of variant):TClientBank;
    property Item[index:integer]:TClientBank read GetItem; default;
    property Last:TClientBank read GetLast;
    property First:TClientBank read GetFirst;

  end;
(* ------------------------------------------------  *)

every property has a method something like this.. This code allows me a lot
of flexibility, and each method can have specific information inserted into
it..


procedure TClientBank.SetAccountNo(const Value:TSerialNumber);
var
  AValue:TSerialNumber;
begin
  AValue := Value; // This line is replaceable with validation code that
gets inserted.
  if AValue <> FAccountNo then
  begin
    if FUpdateCount = 0 then Changing;
    FAccountNo := AValue;
    Modified('AccountNo');
  end;
end;





On Thu, Apr 16, 2009 at 6:17 PM, Paul Heinz <paul at accredo.co.nz> wrote:

> Kyley wrote:
> > Its code generated.. :) I never touch it at all... I have an
> > application I wrote that builds my database, stored
> > procedures, and source code for all the objects etc etc..
> > don't need to try and condense it at all :)
>
> Ah, right. Metaprogamming - the one true way. Data is code. Code is
> data.
>
> In general, I find engineering trade-offs that require less code (that
> human beings had to write) in exchange for providing more meta-data
> (from which code can be automatically generated) is a good trade-off in
> a project of any size or complexity.
>
> Cheers,
>   Paul.
>
>
>
> _______________________________________________
> NZ Borland Developers Group - Delphi mailing list
> Post: delphi at delphi.org.nz
> Admin: http://delphi.org.nz/mailman/listinfo/delphi
> Unsubscribe: send an email to delphi-request at delphi.org.nz with Subject:
> unsubscribe
>



-- 
Kyley Harris
Harris Software
+64-21-671-821
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://listserver.123.net.nz/pipermail/delphi/attachments/20090416/517a541f/attachment-0001.html 


More information about the Delphi mailing list