Tuesday, December 8, 2009

Programming Recipes: Dataflow graph!


Yay! Now I can get down to one of the most useful of all recipes thus far! It's called a dataflow graph, or at least, that's what I call it.

Motivation

So, it's just another typical day at company XYZ, and you're writing some UI code. It's getting a bit hairy, because you have to keep track of updating things on the UI according to changes made to values...
procedure TfrmMain.seAmountChanged(Sender: TObject);
begin
  HandleAmountChanged;
end;

procedure TfrmMain.HandleAmountChanged;
begin
  UpdateSubtotals;
end;

function TfrmMain.GetSubTotal: extended;
begin
  Result := GetProductValue + GetOptionValue;
end;

procedure TfrmMain.UpdateSubTotals;
begin
  lblSubtotal1.Caption := Format('%.2m',[Subtotal]);
  lblSubtotal2.Caption := Format('%.2m',[Subtotal + ShippingTotal]);

  UpdateGrandTotal;
end;

procedure TfrmMain.HandleShippingFlagChanged;
begin
  UpdateGrandTotal;
  UpdateChart;
end;

Yeah, well, you get the idea. Your form is full of values that need to update as the user makes changes or whatnot. Man! All these HandleXXXChanged() and UpdateXXX() procedures are getting complicated! Plus, sometimes different changes require updating values in common, and a value gets updated more than once! That's inefficient! Now I have to add a ton of boolean fields to the form to avoid that, not to mention working out the coordination of the flags with procedure calls...oh, this could be a nightmare!

Or could it be?

There's so much common, repetitive structure to this system. Surely, we could automate something here. As a matter of fact, we can!

Brainstorming

So, what's the deal? Hmm... We have a set of values; each must auto-update when any changes to values that it depends on -- its dependancy values -- occur. Also, we don't want any of the auto-updated values to be computed multiple times, because that's inefficient.

So, we must traverse through a series of updates, preserving the updating order to always update the dependancy values before any of their dependant values are updated. This will allow us to only have to update each single value once.

How will we keep track of dependancies and dependants? We'll have to specify them, since we don't have code reflection for expressions, which would have allowed us to auto-derive the dependancies from expressions. Also, we will want to specify the "formula" for each value only once in the code -- NO duplication, nor any copy and paste. This will avoid inconsistencies and will reduce code size. The best place to specify dependancies is right next to the formula, for easy manual "bookeeping" and checking.

Discussion

So, basically, we have a collection of values that we must always keep consistent with a "formula" that defines them. When a dependancy changes, it's dependant values, to keep consistent with their formulas, will recompute, regarding their formulas as realtime-enforced constraints. So, it's like the new values -- data -- flows, from dependancies, to dependants, automatically. This is called the "dataflow paradigm" (see Wikipedia's article).

And because dependancies can be reused by multiple dependants, the dataflow network structure, rather than forming a tree that branches from dependants to dependancies, forms a graph -- a directed, acyclic graph (no circular references in any formulas). Thus we call this system a "dataflow graph" that we'll design and leverage.

Herein is the abstraction that dataflow graphs provide: Instead of it feeling like we're manually assigning the value to the formula, it feels like we specify the formula for a value only once in the code, and the value automatically keeps itself consistent with its formula, over time!

This should be what we want! A system for keeping track of updating for us!

Getting to Work

First, we start with our declarations:
unit uDG;

interface

type
  //index to a node:
  INode = integer;
...


Now, we want the formula for a value to be close to where we specify the dependancies for it, so we're going to use callbacks:
...
  TNodeAction = (naReadDependancies, naUpdate);

  //manages the implementation of a single node
  //in the dataflow graph:
  TNode = class;

  //our callback for nodes:
  TNodeHandler = procedure(ANode: TNode; AAction: TNodeAction) of object;

To construct our dataflow graph, we're going to have to describe the properties of each node:
...
  //description of a node:
  TNodeDesc = record
    ID: INode;
    EagerlyUpdated: boolean;
    Handler: TNodeHandler;
  end;

And now, the declaration for the TNode Class:
...
  TNode = class
  private
    //reference to its parent TNodes container:
    FList: TNodes;

    //The node's index-ID:
    FID: INode;

    //Maintained lists for all dependancy and dependant values
    //of a node (for efficiency's sake):
    FDependants,
    FDependancies: TINodeSet;

    //The callback:
    FHandler: TNodeHandler;

    //whether is ok to call the ReadDependancies() method of this object:
    FCanReadDependancies,

    //Whether the node, and its dependants
    //should update eagerly when invalidated:
    FEagerlyUpdated,

    //Whether the node is currently in need of being updated:
    FValid: boolean;

    //helper functions as follows...

    function AllDependanciesValid: boolean;

    procedure EnsureInvalidated;
    procedure EnsureDependantsInvalidated;

    procedure EnsureDependantsUpdated;
  public
    constructor Create(AList: TNodes; ADesc: TNodeDesc);
    destructor Destroy; override;

    { we call this function ONLY in the callback, ONLY when asked to get
      a node's dependancies; This procedure can only be called in a callback,
      when the callback is asked to provide dependancies;  if called out of
      context, a runtime error will be thrown (to prevent silent bugs!): }
    procedure ReadDependancies(ADependancies: array of INode);

    { we call the function below after assigning to a variable that has no
      dependancies; if it has dependancies, this function will be called
      automatically: }
    procedure HandleSet;
      { outside of transactions, it performs eager invalidation of dependants,
        followed by eager update of them.

        inside transactions: Performs eager invalidation of dependants,
        deferring updates to the end of the transaction (useful when assigning
        values to multiple independant nodes at once) }

    { the following function performs lazy update (when your nodes are not
      updated eagerly, call this function to update a dependant node, and it
      will automatically update any dependants that need to be, all the way up
      the chain; Warning: do not call inside a transaction! }
    procedure EnsureUpdated;
  end;

And now, the TNodes class -- the container for each TNode:
...
  TNodes = class
  private
    //used to allow recursive transactions:
    FTransactionCount: integer;

    //determines whether to call the callback to update nodes that
    //have no dependancies:
    FComputeIndependantNodes: boolean;

    //the list of nodes:
    FItems: array of TNode;

    //Helper functions...

    function GetItem(ID: INode): TNode;
    function GetNItems: integer;

    procedure Compute(ID: INode);
  public
    constructor Create(AComputeIndependantNodes: boolean;
      Nodes: array of TNodeDesc);

    destructor Destroy; override;

    { functions for doing transactions i.e. assignments to multiple
      independant nodes, so that we're not recomputing dependants for
      each single assignment: }
    procedure BeginTransaction;
    procedure EndTransaction;

    property Items[ID: INode]: TNode read GetItem;
    property NItems: integer read GetNItems;

    property ComputeIndependantNodes: boolean read FComputeIndependantNodes
      write FComputeIndependantNodes;
  end;

//This function is a DSL-like function we will use to specify the properties
//of a node, when we create the dataflow graph:
function Node(AID: INode; AHandler: TNodeHandler = nil;
  AEagerlyUpdated: boolean = True): TNodeDesc;

type
  //A helper class that allows us to use strings in place of integers,
  //for nodeIDs:
  TNodeNames = class
  private
    FNodeIDs: array of string;

    function GetNodeID(AID: string; var AINode: integer): boolean;
  public
    constructor Create;
    destructor Destroy; override;

    //call this function when referring to a string ID that is "new" i.e. when
    //we define the dataflow graph):
    function NewNodeID(AID: string): INode;

    { call this function to refer to an already-existing string ID.
      This function will throw a runtime error if the ID passed is not found
      (good for catching mis-spelled string IDs): }
    function NodeID(AID: string): INode;
  end;

So, there you have it -- the declarations! Now, let's peek under the hood and look at a couple details:
constructor TNode.Create(AList: TNodes; ADesc: TNodeDesc);
begin
  inherited Create;
  ...
  { in the TNode constructor, we call the handler to read its dependancies.
    No handler assumes no dependancies; the FCanReadDependancies flag allows
    us to enforce that no calls can be made to TNode.ReadDependancies(),
    except at this point: }
  if Assigned(FHandler) then
    begin
      FCanReadDependancies := True;
      FHandler(Self, naReadDependancies);
    end;
  FCanReadDependancies := False;
end;

Take a look at these next two routines:
procedure TNode.EnsureInvalidated;
begin
  //only invalidate if already valid
  if not FValid then Exit;

  FValid := False;
  EnsureDependantsInvalidated;
end;

procedure TNode.EnsureDependantsInvalidated;
var
  iDependant: integer;
begin
  for iDependant := Low(FDependants) 
   to High(FDependants) do
     FList.Items[FDependants[iDependant]].EnsureInvalidated;
end;

As we can see, invalidating a node will recursively traverse down to its dependants, and its dependant's dependants, etc.
//when a node has been set,
procedure TNode.HandleSet;
begin
  //it's now valid
  FValid := True;
  
  //but now all dependants need to be updated  
  EnsureDependantsInvalidated;

  { after invalidating all dependants, now we
    update all dependants, but only if we're not
    inside a transaction, which will do this for us! }
  if FList.FTransactionCount = 0 then
    EnsureDependantsUpdated;
end;

Notice the next routine:
procedure TNode.EnsureDependantsUpdated;
var
  iDependant: integer;
begin
  for iDependant := Low(FDependants) to High(FDependants) do
    if FList.Items[FDependants[iDependant]].FEagerlyUpdated then
        FList.Items[FDependants[iDependant]].EnsureUpdated;

  for iDependant := Low(FDependants) to High(FDependants) do
      if FList.Items[FDependants[iDependant]].FEagerlyUpdated then
          FList.Items[FDependants[iDependant]].EnsureDependantsUpdated;    
end;

So, why don't we just use the same recursion for updating dependants as we do for invalidating dependants? Because, in order to avoid updating dependants before ALL their dependancies are ready to use, we must perform a breadth-first traversal of nodes. The other way would perform a depth-first traversal, resulting in some node down the chain trying to update itself with dependancies that we haven't traversed to and invalidated or updated yet.

Ok, last but not least:
procedure TNode.EnsureUpdated;
var
  iDependancy: integer;
begin
  { We mustn't call this procedure within a transaction; the library is
    guaranteed to never call this procedure in a transaction, so this assertion
    will only go off if the programmer using the library makes a mistake: }
  Assert(FList.FTransactionCount = 0);
  
  //only update a node if it's not yet updated:
  if FValid then Exit;

  //update each dependancy node: notice that we do a depth-first, recursive
  //traversal down to all dependancy nodes, with this:
  for iDependancy := Low(FDependancies) to High(FDependancies) do
    FList.Items[FDependancies[iDependancy]].EnsureUpdated;

  //handle calling the callback, which performs the actual
  //calculation of the node:
  FList.Compute(FID);

  //and now we're valid:
  FValid := True;
end;

That's all the implementation I'm going through -- the main core. One of my methodologies is that the quickest way to learn how to use a library is to see examples, or use-cases, of it, so now let's see what it looks like to USE this library!

Example

Below is a small-scale example -- the full listing of an example form, with comments:
unit Unit1;

interface

uses
  //Standard Delphi 4 Units:
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Spin, Math,

  //Our dataflow graph library:
  uDG;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    SpinEdit1: TSpinEdit;

    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);

    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure SpinEdit1Change(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }

    //our DG library's data structures:
    FNodes: TNodes;
    FNodeNames: TNodeNames;

    //values of the form:
    FFlag: boolean;
    FLastMousePos: TPoint;

    //callbacks for each non-independant node:
    procedure HandleNode_CanvasPenWidth(ANode: TNode; AAction: TNodeAction);
    procedure HandleNode_Label1Caption(ANode: TNode; AAction: TNodeAction);
    procedure HandleNode_Label1Position(ANode: TNode; AAction: TNodeAction);
    procedure HandleNode_Label2Caption(ANode: TNode; AAction: TNodeAction);
    procedure HandleNode_Label3Caption(ANode: TNode; AAction: TNodeAction);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.HandleNode_CanvasPenWidth(ANode: TNode; AAction: TNodeAction);
begin
  case AAction of

    { time to get the dependancies for this node; note that you can only call
      the following method in a callback, when AAction is assigned the given
      value here: }
    naReadDependancies:ANode.ReadDependancies([
      FNodeNames.NodeID('SpinEdit1.Value')
    ]);

    { time to compute the value of this node; notice how the value for
      Canvas.Pen.Width depends on the value for SpinEdit1.Value; this is why
      we have SpinEdit1.Value in the call to ReadDependancies() above; our
      dataflow graph will automatically update dependant values when their
      dependancies are flagged as changed; in this case, the following code
      will be run: }
    naUpdate:Canvas.Pen.Width := Max(SpinEdit1.Value, 1);
  end;
end;

procedure TForm1.HandleNode_Label1Caption(ANode: TNode; AAction: TNodeAction);
begin
  case AAction of
    naReadDependancies:ANode.ReadDependancies([
      FNodeNames.NodeID('SpinEdit1.Value')
    ]);
    naUpdate:Label1.Caption := IntToStr(SpinEdit1.Value);
  end;
end;

procedure TForm1.HandleNode_Label1Position(ANode: TNode; AAction: TNodeAction);
begin
  case AAction of
    naReadDependancies:ANode.ReadDependancies([
      FNodeNames.NodeID('FLastMousePos'),
      FNodeNames.NodeID('Canvas.Pen.Width')
    ]);
    naUpdate:begin
      Label1.Left := Round(0.2*FLastMousePos.x + 0.8*Label1.Left);
      Label1.Top := Round(0.2*FLastMousePos.y + 0.8*Label1.Top);

      Canvas.LineTo(Label1.Left, Label1.Top);
    end;
  end;
end;

procedure TForm1.HandleNode_Label2Caption(ANode: TNode; AAction: TNodeAction);
begin
  case AAction of
    naReadDependancies:ANode.ReadDependancies([
      FNodeNames.NodeID('SpinEdit1.Value'),
      FNodeNames.NodeID('FFlag')
    ]);
    naUpdate:Label2.Caption := IntToStr(SpinEdit1.Value+Ord(FFlag));
  end;
end;

procedure TForm1.HandleNode_Label3Caption(ANode: TNode; AAction: TNodeAction);
begin
  case AAction of
    naReadDependancies:ANode.ReadDependancies([
      FNodeNames.NodeID('FFlag')
    ]);
    naUpdate:
      if FFlag then
        Label3.Caption := 'True' else
          Label3.Caption := 'False';
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  //create the TNodeNames helper class
  FNodeNames := TNodeNames.Create;

  //use it here; notice I'm calling its NewNodeID() method,
  //to "declare" new node IDs:
  with FNodeNames do
    FNodes := TNodes.Create(True, [
      Node(NewNodeID('FLastMousePos')),
      Node(NewNodeID('Canvas.Pen.Width'), HandleNode_CanvasPenWidth),
      Node(NewNodeID('Label1.Caption'), HandleNode_Label1Caption),
      Node(NewNodeID('Label1.Position'), HandleNode_Label1Position),
      Node(NewNodeID('Label2.Caption'), HandleNode_Label2Caption),
      Node(NewNodeID('Label3.Caption'), HandleNode_Label3Caption),
      Node(NewNodeID('FFlag')),
      Node(NewNodeID('SpinEdit1.Value'))
    ]);

  //the transaction to initialize all values:
  FNodes.BeginTransaction;
  FLastMousePos.x := 30;
  FLastMousePos.y := 30;
  FFlag := False;
  FNodes.EndTransaction;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FNodes.Free;
  FNodeNames.Free;
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; 
  X, Y: Integer);
begin
  //assign an independant node's values:
  FLastMousePos.x := X+Random(5)-2;
  FLastMousePos.y := Y+Random(5)-2;

  //tell the dataflow graph that we just assigned to an INDEPENDANT node's
  //values; it will update the dependant values for us:
  FNodes.Items[FNodeNames.NodeID('FLastMousePos')].HandleSet;
end;

procedure TForm1.SpinEdit1Change(Sender: TObject);
begin
  FNodes.Items[FNodeNames.NodeID('SpinEdit1.Value')].HandleSet;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  FFlag := not FFlag;
  FNodes.Items[FNodeNames.NodeID('FFlag')].HandleSet;
end;

end.

Conclusion

Well, that's today's programming recipe! Hope you've gotten something useful out of this! Below is the source code for both the library and the example:

Library Source
Example Source

Thursday, November 12, 2009

Power Tip: 'With'-Helpers


In the previous article, I mentioned that Delphi includes a 'with' statement, and although it seems like an unimportant for a language to have, I'm going to teach you something that will make you stand back and give you an alternate perspective on this simple mechanism. Sorry all you C++ fans, this power tip applies only to languages that have a 'with' statement.

With statements are the most useful for one thing: 'with'-helpers.

What is a 'with'-helper?

Yeah, I knew you were thinking that: a 'with'-helper is a class or data structure that is designed to be more convieniently used via a 'with' statement in Delphi. It's one of the most Ruby-like features that Delphi has to offer, brining a greater increase of convenience and fun to Delphi programming. The most quick way to demonstrate is through examples, so come on, let's take a look...

Examples

Let's start with a simple example: a work-around for variables. In Dephi, one normally has to explicitly declare variables before the block of code that uses them begins, like so:
procedure ReportMyError(Code: integer);
var
  //we're declaring the variable here in the "var" block
  vMsg: string;
begin
  if Code > 0 then
    if GetErrorMsgStr(Code, vMsg) then
      PrintLn('Error!'#13#10 + vMsg);
end;

This can quickly become inconvenient, so, why don't we create a 'with'-helper that provides a temporary string variable:
type
  TStringValue = record
    Value: string;
  end;

function StringValue: TStringValue;
begin
  Result.Value := '';
end;

And then use it like so:
procedure ReportMyError(Code: integer);
begin
  if Code > 0 then
    //calling the StringValue() function to create a new string value,
    //which is put into the context with the "with" statement:
    with StringValue do
      if GetErrorMsgStr(Code, Value) then
        PrintLn('Error!'#13#10 + Value);
end;

Did you notice where identifier called 'Value' came from? 'Value' was implicitly referenced from the TStringValue record returned by the StringValue() call and implicitly put in scope by the 'with' statement. Get all that? Thanks to Delphi's built-in support for records, we don't do any memory management! Yay! Delphi is better!

We can do much better than this, however. Let's create a nice 'with'-helper for providing the effect of a 'let' statement: create and compute a value, sort of like a closure:
type
  TFloatValue = record
    Value: extended;
  end;

function FloatValue(AValue: extended): TFloatValue;
begin
  Result.Value := AValue;
end;

Now we use it:
function EmitRatios(A, B: extended);
begin
  with FloatValue(Sqrt(Sqr(A)+Sqr(B))) do
    begin
      PrintLn(FloatToStr(Value/A));
      PrintLn(FloatToStr(Value/B));
    end;
end;

Sweet! The value passed to FloatValue() was only computed once! Yay for the extra efficiency boost! Records can do some good and come in handy-dandy using them. Along with what we've seen, we can also return multiple results from functions, capture them with a 'with' statement, and leverage them thus. But there's one problem with this last example: records can only do so much: their fields are mutable and cannot be protected from writing to them. This could cause horrible bugs in a program if we're not careful. Thus, we move on up to using classes as 'with'-helpers. Here's our previous example modified:
type
  TFloatValue = class
  private
    FValue: extended;
  public
    property Value: extended read GetValue;
  end;

function FloatValue(AValue: extended): TFloatValue;
begin
  Result := TFloatValue.Create;
  Result.FValue := AValue;
end;

//using it:

function EmitRatios(A, B: extended);
begin
  with FloatValue(Sqrt(Sqr(A)+Sqr(B))) do
    try
      PrintLn(FloatToStr(Value/A));
      PrintLn(FloatToStr(Value/B));
    finally
      Free;
    end;
end;

Notice the try-finally block for freeing the created class called by and provided for the 'with' statement. Delphi knows that the structure used by the 'with' statement should have its members in the enclosing scope, so this technique will also work even if the 'with' statement is already inside a class method.

Now that we're using classes, we can do more sophisticated stuff, seeing as classes provide not only properties, but methods. As a last example:
type
  TTokens = array of TToken;

procedure Append(AToken: TToken; var Tokens: TTokens);
begin
  SetLength(Tokens, Succ(Length(Tokens)));
  Tokens[High(Tokens)] := AToken;
end;

function ScanTokens(AStr: string): TTokens;
begin
  SetLength(Result, 0);
  //constructs a TScanner class, giving it the 
  //string to scan: TScanner = token iterator
  with Scanner(AStr) do
    try
      while ReadNextToken do //TScanner.ReadNextToken method
        Append(CurToken, Result); //TScanner.CurToken property
    finally
      Free;
    end;
end;

Conclusion

Thanks for learning. Hope you enjoyed this power tip. Happy coding!

Tuesday, November 3, 2009

Be Advised: C++ vs Delphi

While thinking about what knowledge would be of most use to the rest of programmerdom, I realized that an objective, non-biased, experienced, comparison between C++ and Delphi would provide valuable information to one and all, that all may be more educated as to the tradeoffs of these languages, their pros and cons, and perhaps be able to glean valuable insight to pass on to the next generation of programming languages.

I hear that everybody loves flamewars. If you’ve come for that, please leave now.

Still here? Ok, nice. If you’re like me, you know that anyone who is wedded to programming language X, has not spent enough time in their lives programming nor studying programming languages, to have serious experience with or understanding of programming languages. However, if you are one who has come for an experienced comparison of C++ and Delphi, well, you will not have wasted your time (inasmuch as I’m not restating what you already know). Let me just give 1 caveat: I have much more experience with Delphi than with C++, so I may have left a couple of advantageous features of C++ out. If I do so, please remind me, and I will be sure to include such (provided they meet the criteria of being exclusive, marked advantages.) Now, enough with the fluff, let’s get down to the meat. The following lists features that vary from Delphi to C++, listing the winning language:

FeatureWinnerExplanation
ClosuresDelphiC++ just doesn't have closures. Closures are an advantageous way to organize long procedures of code into smaller, more reusable pieces.
Operator OverloadingC++Delphi doesn't have this feature. Operator overloading is useful for terse arithmetic libraries over different kinds of quantities, such as intervals, bignums, and others, instead of having to invoke a bunch of method calls by name. In addition, expressions can be semantically overloaded and more reusable via OOP.
InterfacesDelphiC++ doesn't have interfaces. Interfaces are like mixins without implementations: they provide a description of a set of methods that a class would need to implement to be compatible with the interface. Subroutines can use interfaces to be more generic and reusable, by accepting, as a parameter, any object that implements a specified interface. Classes in Delphi can implement as many interfaces as they like. This provides a simple alternative to multiple inheritance.
Multiple InheritanceC++Delphi just doesn't have multiple inheritance. Multiple inheritance is where an object can inherit fields and methods from more than one base class. In practice, this is very complicated and is usually overkill, but for those situations in which it makes sense, C++ provides this alternative.
PropertiesDelphiIn C++, one must use getters and setters to write to the properties of a class. In Delphi, one describes properties, and can direct reading and writing to either a field or a getter and setter method, or describe whether a property can even be read from or written to. In addition, one can reference a property via the dot notation. e.g. "GoButton.Enabled" and use such an expression for reading and writing, without having to directly invoke getters and setters. This provides better abstraction.
Module SystemDelphiIn C++, you have header files and C++ files. The header file declares what code is available to other C++ files. The preprocessor is assigned with the task of providing each C++ and header file with knowledge of its dependencies. In Delphi, a module is a single file called a unit. The unit lists what code is public to other units (called the interface of the unit), as well as housing the implementation of the public declarations. Units lists their dependency on other units via the "uses" clause. In addition, Delphi provides optional initialization and finalization sections, so that the unit can initialize or free any internal state it uses. These features all provide for a much more robust seamless module system, giving each unit airtight encapulation facility. Of course, Delphi is a member of the Pascal family of languages, which are all known for their robust module systems.
Constructors and Stack ObjectsC++C++ has a standard system for copying objects, in addition to the normal constructor used for creating objects. This streamlines this utility. In addition, C++ then provides a way to declare object variables that are automatically created and managed on the stack. This provides better abstraction for temporary helper objects, which can then be treated as data types. In Delphi, however, all objects are created on the stack, and must be explicitly created and freed. Object variables are actually assignable, nullable references to object instances. Also, Delphi does not have a built-in system for copying objects or assigning their values around, although there is a standard method convention used for assigning objects to each other.
Templates and Generic ClassesC++Delphi does not have templates, nor does it have generic classes. This means that algorithms and data structures must be implemented differently for objects and primitive types. C++ provides templates, which allow any piece of code to be reused for different, but compatible, types, primitive or not.
Method PointersDelphiDelphi provides well-developed facilities for managing pointers to methods and subroutines. This comes in handy for event-handling code and other related uses. C++ on the other hand, is very messy, requiring one to get into some hairy types. Generally, using pointers to methods or subroutines, is not recommended. Instead, C++ relies on templates to facilitate the coupling of objects to event handlers.
Error MessagesDelphiC++'s error messages are often cryptic and do not provide intuitive or simple feedback to the programmer. Delphi always provides simple, direct error messages (although both languages use programming-centric terminology).
Encapsulated Class DefinitionsC++C++ allows one to declare a class inside a class. This is useful in some cases, so C++ provides the option. As far as I know, Delphi does not.
HackerinessC++C++ is more all-around hacker-frendly, and relies more on the use of symbols and operators, making it, in comparison to natural language, more cryptic. Delphi uses alot more english words and alot less symbols, for its code. Of course, experience with either, will render this difference negligible, but hackers tend to enjoy symbols more.
ReferencesC++C++ has references as a type. References are a more abstract version of pointers, and have lean implementations. Thus, they can come in handy for simplifying code and making it more readable. Delphi, while allowing one to pass parameters around by reference, does not have a reference type -- just pointers.
Dynamic ArraysDelphiDelphi has built-in, leanly-implemented, runtime-resizeable arrays of any dimension. These can come in handy in many situations, since Delphi lacks generics. C++ has no such thing, instead relying on its generics to achieve the same functionality.
Strings and String ManagementDelphiDelphi has built-in, leanly-implemented, memory-managed strings. Thus, using strings in Delphi is a breeze. The same is not so true for C++, but it covers most all of the ground, in ease-of-use, with its String class.
Compilation TimeDelphiDelphi was designed to compile fast, and to only compile the units that have changed since their last compile. Thanks to its module system, this is more easily achievable. In practice, this means that the compile-run cycle is quick, since the compiler will only compile the units you make changes to.
In-block VariablesC++C++ allows one to declare variables anywhere inside a block of code. This is much more convenient for writing code than in Delphi, which requires all variables to be declared in the declarations section, preceding the implementation blocks of code. Although one might argue that there's a trade-off between more readable code and more writable code. But I'd prefer C++'s choice on this one.
VariantsDelphiDelphi provides a primitive type called a Variant, which is simply a data type that can only any other primitive type (no compound types, pointers, objects, or dynamic arrays). This can be useful in situations where one would otherwise have to write lots of type-handling code. This type as evolved into the OLEVariant type, which allows Delphi programmers a choice when coding for COM and OLE automation, between early-bound and late-bound style.
SetsDelphiDelphi's equivalent to C++'s enumeration type, is much more well-abstracted. Delphi provides set union and difference operators.
Open Array ParametersDelphiIn addition to dynamic arrays, Dephi provides a way to pass arrays as parameters. It even provides a notation for declaring array-literals as parameters. e.g. "PrintLn(["hi",a,"two",x])" This is extremely handy when developing and using DSL-like libraries, such as parsers. C++ doesn't quite have this functionality.
"with" statementDelphiC++ does not have "with" statements. "With" statements are very useful for unraveling repeated object references and putting the referenced object's properties and methods automatically in the local scope. This seems like a trivial convenience, but we'll see later on why it's such an important ingredient to the repertoire of delphi's constructs.

Conclusion

So, after looking over this list of features, there's a couple of patterns that stand out -- consistent language design choices made. Delphi is intended to be an applications programming language, seeking to provide for more abstraction in many common areas -- strings, modules, open array parameters, late-bound COM programming. This is a common thread running through the design decisions of Delphi. Don't get me wrong, it's also intended to create programs of competitive efficiency with C++, but the point is that Delphi is focused on providing more abstraction for applications programmers. C++ is a systems programming language, designed to not trade a single bit of efficiency away for abstraction. It tries to do what it can for abstraction, but the guiding principle, indeed, the constraint, upon C++, is that there is nothing in the language that prevents the programmer from hand-optimizing efficiency. Language design choices are a different subject altogether, though. Just remember that language differences don't necessarily imply general superiority or inferiority. C++ is a better systems language, and Delphi is a better applications language. Each has its own optimal role.

Introduction

Hi!

Welcome to the overcoded! blog. My name is Winheim Raulsh. I am the writer of this blog and will be your guide, that you may better navigate this trove of information I periodically gather together and spill onto pages. I am a Delphi programmer by birth, and have come to know many languages like C++, Lua, and others, but mainly I will stick to my native language: Delphi.

Delphi is my default choice, as I have been programming in it for years, and it has served me well. Delphi is a systems and desktop programming language available for developing on the Win32 platform, hence it is very fast (comparable to C++) so that programs can scale without having to be rigorously optimized, yet it is a more high-level language. Delphi, ah, Delphi. It has its limitations, and isn’t anything particularly spectacular, but it can do many good things. I’ve learned most everything I ever would need to know about Delphi, and then some — all this knowledge wrapped up in my head, with nothing to do with it, so I started this blog for really no reason, except simply to kill time and do fun things with Delphi, just because I can. That’s where the name for this blog comes from: excess pointless Delphi coding for no great, grand reason — my life is overcoded.

Sometimes, I wish I could program in Lua instead. Lua is different; it doesn’t scale; you can’t write 20k LOC programs in it, you run very complex or tight computations in it, without the speed bogging down; nor is it a systems programming language with access to all of the Win32 api, nor does it come with all the useful, pre-developed gui libraries, database access, and other stuff that comes with Delphi. It’s only a scripting language, all by itself, so I’m stuck with Dephi. And that, ladies and gentlemen, is a classic case in a high barrier-to-entry, in the world of software development.

Now, where was I? Ah, yes: let me give a grand tour of how we do things around here. As I was thinking about what kinds of articles to do, I liked the idea of having different series of ongoing articles, so pretty much all articles are a part of one series or another. How did I come tho that? Basically, I narrowed down the basic purposes of different articles I would write to only a handful. It really helps one to quickly determine what the articles are throwing at you. As a blogger, I will stick close to the purpose and subject of my entries, so don’t expect much philosophical discussion, unless you’re forewarned with a title or section header, ’cause I’ll be keepin’ it on-topic.

Series

The following is a tour-guide of the different types of entries I’ll write.

Be Advised

These articles contain relatively refined knowledge and experience of practical things pertaining to software development. If I have been there, studied the issues, and have a well-developed knowledge of the situation, then consider these articles as troves of useful information to take into consideration while making decisions, or for future reference.

Power Tip

These articles contain various useful coding tricks and practical techniques for improving your development experience. They are very narrow, focused, specific things you can do. These tips are straightforward and easy to wrap your head around; they don’t require pondering to understand.

Goodies

These articles introduce free code libraries & other such stuff that I provide online! They will document such things as why, basic usage, and a download link. Feel free to use the code according to the license embedded within its downloaded version, otherwise it implicitly falls under the Create Commons Attribution-ShareAlike 3.0 License.

Queries

These articles are an opportunity for me to ask you, the reader, to enlighten me with valuable insight or information on something I can’t quite seem to grok. Explain away! Comments welcome! (Not that they’re unwelcome in other situations.) BTW, thanks in advance!

Reflections

Obviously, if I have something I feel is very important to say — something I’ve reflected upon, probably theoretical or philosophical, that helps me understand or achieve insight into the vastly complex world of programming or programming languages — I will put it in this category. Feel free to express your thoughts (on-topic, of course). I guess I would really only expect two types of responses: affirmations & critiques. ‘Course, you can criticize the ideas all you like (I don’t mind). If you find the ideas useful, please comment on how exactly so.

Programming Recipes

Unlike Power Tips, these entries get deep into the nitty-gritty of larger code solutions to various problems — recipes to code. Perhaps some of the problems can be requested by you. First, I’ll start off with an explanation of the problem, followed by an overview of the solution, followed by a laid-out, detailed walkthrough of the coding. Think of the programming version of a chef show on TV, and you have a good idea of what these articles are for. Please feel free to evaluate my solutions and suggest corrections! All your constructive feedback will especially help!

Enlightenment

Enlightenment is my explanations of concepts when I finally grok them, that is, not just what they are, but why they are, where they come from, and what they do for us. These are the kinds of things I wished computer scientists and instruction materials (all on the internet) had explained to me in terms that are familiar and clear, so feel free to learn new things, and hopefully, you can find enlightenment as well!

Conclusion

So, that’s the tour! Thanks for stopping in, now, enjoy the journey as your life becomes overcoded!