<br><div>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.</div>
<div><br></div><div>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.</div>
<div>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.</div>
<div><br></div><div>apart from the code generated managed objects, i doubt I have many units of code &gt; 15,000.</div><div><br></div><div>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. <br>
</div><div><br></div><div>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&#39;t need to save time.. it is built for me.</div>
<div>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..  </div><div><br></div><div>example of 1 such generated object. ( I will pick a small one)  Those lines also tend to include comments and documentation..</div>
<div>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.. </div>
<div><br></div><div>(*  THIS IS JUST A PORTION OF AN INTERFACE SECTION *)</div><div><div>  TCLIENTBANK_CLIENTBANKID = &#39;ClientBankID&#39;; </div><div>  TCLIENTBANK_LASTMODIFIED = &#39;LastModified&#39;; </div><div>  TCLIENTBANK_CLIENTID = &#39;ClientID&#39;; </div>
<div>  TCLIENTBANK_BANKBRANCHID = &#39;BankBranchID&#39;; </div><div>  TCLIENTBANK_ACCOUNTNO = &#39;AccountNo&#39;; </div><div>  TCLIENTBANK_DRAWERNAME = &#39;DrawerName&#39;; </div><div><br></div><div><br></div><div>  TClientBank = class(TItem)</div>
<div>  private</div><div>    FClientBankID:TItemPrimaryKey;</div><div>    FLastModified:TDateTime;</div><div>    FClientID:TItemPrimaryKey;</div><div>    FBankBranchID:TItemPrimaryKey;</div><div>    FAccountNo:TSerialNumber;</div>
<div>    FDrawerName:string;</div><div>  protected</div><div>    procedure SetClientBankID(const Value:TItemPrimaryKey);</div><div>    function GetLastModified:TDateTime;</div><div>    procedure SetLastModified(const Value:TDateTime);</div>
<div>    procedure SetClientID(const Value:TItemPrimaryKey);</div><div>    procedure SetBankBranchID(const Value:TItemPrimaryKey);</div><div>    procedure SetAccountNo(const Value:TSerialNumber);</div><div>    procedure SetDrawerName(const Value:string);</div>
<div>  protected</div><div>    function GetDisplayName: string; override;</div><div>  public</div><div>    constructor Create(Items:TItems);override;</div><div>    destructor Destroy;override;</div><div>    class function TagName:string; override;</div>
<div>    class function PrimaryField:string;override;</div><div>    class function ObjectVersion:integer;override;</div><div>    function Clone(AOwner:TItems=nil):TClientBank;</div><div>  published</div><div> { Auto Generated Field for the database } </div>
<div>    property ClientBankID:TItemPrimaryKey read FClientBankID write SetClientBankID;</div><div> { Auto Generated Field for the database } </div><div>    property LastModified:TDateTime read GetLastModified write SetLastModified;</div>
<div>    property ClientID:TItemPrimaryKey read FClientID write SetClientID;</div><div>    property BankBranchID:TItemPrimaryKey read FBankBranchID write SetBankBranchID;</div><div>    property AccountNo:TSerialNumber read FAccountNo write SetAccountNo;</div>
<div>    property DrawerName:string read FDrawerName write SetDrawerName;</div><div>  end;  </div><div><br></div><div>  TClientBankIndex = class;</div><div>  TClientBanks = class(TItems)</div><div>  private</div><div>    function GetItem(Index: Integer): TClientBank;</div>
<div>    procedure SetItem(Index: Integer; const Value: TClientBank);</div><div>    function GetFirst:TClientBank;</div><div>    function GetLast:TClientBank;</div><div>    function GetNext(AItem: TItem): TClientBank;</div>
<div>    function GetPrevious(AItem: TItem): TClientBank;</div><div>  public</div><div>    class function GetItemClass:TItemClass;override;</div><div><br></div><div>    function DefaultIndexClass:TItemIndexClass;override;</div>
<div>    function NewIndex(IndexName:string;IndexFields:string;FieldLookup:TFieldReplaceEvent=nil;ItemFilter:TItemFilterEvent=nil):TClientBankIndex;</div><div>    function GetIndex(IndexName:string):TClientBankIndex;</div>
<div><br></div><div>    function Add(AClass:TItemClass=nil): TClientBank;</div><div>    function Insert(Index: Integer): TClientBank;</div><div>    function GetItemByPrimaryKey(AKey:TItemPrimaryKey):TClientBank;</div><div>
    property Items[Index: Integer]: TClientBank read GetItem write SetItem;default;</div><div>    property First:TClientBank read GetFirst;</div><div>    property Last:TClientBank read GetLast;</div><div>    property Previous[AItem:TItem]:TClientBank read GetPrevious;</div>
<div>    property Next[AItem:TItem]:TClientBank read GetNext;</div><div>  end;</div><div><br></div><div>  TClientBankIndex = class(THsAvlItemNonUniqueIndex)</div><div>  protected</div><div>    function GetItem(index: integer): TClientBank;</div>
<div>    function GetFirst:TClientBank;</div><div>    function GetLast:TClientBank;</div><div>  public</div><div>    {@@ returns the ordinal position of the item in the index.}</div><div>    function PositionOfItem(AItem:TClientBank):integer;</div>
<div>    function IndexPositionOfItem(AItem:TClientBank):integer;</div><div>    {@@ find an item based on index data}</div><div>    function Find(Values:array of variant):TClientBank;</div><div>    property Item[index:integer]:TClientBank read GetItem; default;</div>
<div>    property Last:TClientBank read GetLast;</div><div>    property First:TClientBank read GetFirst;</div><div><br></div><div>  end;</div><div>(* ------------------------------------------------  *)</div><div><br></div>
<div>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..</div><div><br></div><div><div><br></div><div>procedure TClientBank.SetAccountNo(const Value:TSerialNumber);</div>
<div>var</div><div>  AValue:TSerialNumber;</div><div>begin</div><div>  AValue := Value; // This line is replaceable with validation code that gets inserted.</div><div>  if AValue &lt;&gt; FAccountNo then</div><div>  begin</div>
<div>    if FUpdateCount = 0 then Changing;</div><div>    FAccountNo := AValue;</div><div>    Modified(&#39;AccountNo&#39;);</div><div>  end;</div><div>end;</div><div><br></div></div><div><br></div><div><br></div></div><div>
<br></div><div><br></div><div>On Thu, Apr 16, 2009 at 6:17 PM, Paul Heinz <span dir="ltr">&lt;<a href="mailto:paul@accredo.co.nz">paul@accredo.co.nz</a>&gt;</span> wrote:<br></div><div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="im">Kyley wrote:<br>
&gt; Its code generated.. :) I never touch it at all... I have an<br>
&gt; application I wrote that builds my database, stored<br>
&gt; procedures, and source code for all the objects etc etc..<br>
&gt; don&#39;t need to try and condense it at all :)<br>
<br>
</div>Ah, right. Metaprogamming - the one true way. Data is code. Code is<br>
data.<br>
<br>
In general, I find engineering trade-offs that require less code (that<br>
human beings had to write) in exchange for providing more meta-data<br>
(from which code can be automatically generated) is a good trade-off in<br>
a project of any size or complexity.<br>
<br>
Cheers,<br>
<font color="#888888">  Paul.<br>
</font><div><div></div><div class="h5"><br>
<br>
<br>
_______________________________________________<br>
NZ Borland Developers Group - Delphi mailing list<br>
Post: <a href="mailto:delphi@delphi.org.nz">delphi@delphi.org.nz</a><br>
Admin: <a href="http://delphi.org.nz/mailman/listinfo/delphi" target="_blank">http://delphi.org.nz/mailman/listinfo/delphi</a><br>
Unsubscribe: send an email to <a href="mailto:delphi-request@delphi.org.nz">delphi-request@delphi.org.nz</a> with Subject: unsubscribe<br>
</div></div></blockquote></div><br><br clear="all"><br>-- <br>Kyley Harris<br>Harris Software<br>+64-21-671-821<br>
</div>