Categories
Commentary

Hidden features in the Delphi Object Pascal language

A list of hidden features in Delphi Object Pascal that are great, obscure, best avoided or remarkable.

This was copied from Stack Overflow’s question of the same name which is closed and flagged for deletion. Licensed under cc by-sa 3.0 with attribution required. I’ve made a few changes, updates and some copy editing. Original question by Johan and others on May 19 2011 at 18:34. Post inspired by Jeroen W. Pluimers’ post.


David M added:

My favourite (although I don’t know if I have ever written code that uses this) is how you can delegate implementation of an interface ‘supported’ by a class to one of the class’s properties. In a pure OO design sense, I don’t know if this is awful or beautiful – you’re basically lying about what your class’s methods are – but in a code cleanliness and separation sense it’s awesome.

For example (untested, written from memory):

type
IFoo = interface
['{3F996D68-1FD0-4490-AE60-8F735A9DFFE8}']
    function TheQueensHead: Byte; // Geddit?  They're bars 
    function TheBoar: Byte;
    function TeeFortyTwo: Byte;
  end;</p>
<p>TOnTheTown = class(TInterfacedObject, IFoo)
  private
    FFoo: TFoo; // Some class that actually concretely implements IFoo
  public
    constructor Create();
    property Foo: TFoo read FFoo implements IFoo; // This keyword is the awesome one
  end;

Now, if I remember my Delphi correctly (I mostly use C++ these days) you can call:

Party := TOnTheTown.Create();
Party.TheBoar;

where TheBoar is shown in the class declaration as implemented by that class, but code-wise you implement it in the class that the property Foo is of – the call is delegated to the property. Neat, isn’t it?

Even better, I just learned this very day while googling to check my memory was correct that starting with XE, you can do this in C++ too.

Either declare Party as IFoo or, perhaps, cast it (Party as IFoo). The point is that you have an object that you state implements various methods (because it claims to implement a particular interface) and yet it doesn’t – calls are redirected / delegated somewhere else.


Andreas Rejbrand added:

You can use & to prefix identifiers that would normally be invalid because they are reserved words.

procedure TForm1.Button1Click(Sender: TObject);
var
  &amp;begin,
  &amp;if,
  &amp;end: integer;
begin
  &amp;begin := 10;
  &amp;if := 100;
  &amp;end := 1000;
  ShowMessage(IntToStr(&amp;begin + &amp;if + &amp;end));
end;

You can use the ^A syntax to denote a Ctrl+A ‘character’:

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
  if Key = ^C then
    ShowMessage('The user wants to copy something.')
  else if Key = ^V then
    ShowMessage('The user wants to paste.')
end;

Something I have always found a bit funny is the compiler magic associated with the TGUID type. This is declared as

TGUID = packed record
  D1: LongWord;
  D2: Word;
  D3: Word;
  D4: array[0..7] of Byte;
end;

and so, a priori, one would not expect something naïve like

const
  g: TGUID = '{E4C26C63-CDD1-4450-9FE0-6F035E33CF90}';

to work, but it does. Compiler magic, it is!

One would expect

[DCC Error] Unit1.pas(27): E2010 Incompatible types: 'TGUID' and 'string'

Sertac Akyuz added:

Construct a dynamic array using it’s type’s constructor:

type
  TInts = array of Integer;

..

var
  Ints: TInts;
begin
  Ints := TInts.Create(3, 5, 1, 0, -2, 5);
end;

Not sure if this is documented or not but when I learned this from a newsgroup post after years of using Delphi, I was a bit surprised.

PS: Do not Free the array. 🙂


Cosmin Prund brought up The ABSOLUTE keyword.

This is a nice way to shoot yourself in the foot, because it throws type-safety out the window big time. Delphi’s RTL sources uses this in 5 different units. The first 4 only use it once per unit, then there’s Mxarrays.pas where this is used 22 times. What I’m trying to say is that the absolute keyword is rarely used.

// This is how it's useful:
procedure Test;
var i64: Int64;
    b:array[0..7] of Byte absolute i64; // starts at the same memory space as i64
begin
  i64 := 7;
  WriteLn(b[3]);
end;

// This is how you shoot yourself in the foot:
procedure Test;
var s: string;
    i: NativeInt absolute s;
begin
  s := 'Test';
  Dec(i, 7);
  ShowMessage(s); // will give you garbage or AV
end;

Variant records are weired-looking records where some part of the record is “variable”. Every time I see one used I say That’s an useful trick, but never managed to actually use one in my own code. And I do use weird unsafe things like the absolute keyword and pointer arithmetic.

Example:

type
  TKindOfShape = (ksCircle, ksSquare);

  Shape = record
    case Kind:TKindOfShape of
      ksCircle:
        (
          R: Double;
          CenterX, CenterY: Double;
        );
      ksSquare:
        (
          Top, Left, SideSize: Double;
        );
  end;

Warren Postma brought in some ancient syntax:

Not so much hidden, as ancient are the digraphs supported by the original Wirth pascal, which still work in Delphi:

procedure Dummy;
var
   a:array (. 0 .. 2 .) of Integer;
begin

end;

The character sequence (. and .) replace [ and ] on systems where the [ and ] are not even available, and are called digraphs because they are two characters. C/C++ for example, supports some Trigraphs (three character symbols), too.

I think most Delphi programmers have seen comments that are written with (* and *) which are the common digraph form of { and }.


lkessler added:

Almost everyone knows about the increment and decrement function:

Inc(N) // to increment N by 1.
Dec(N) // to decrement N by 1.

But did you know they have a second parameter, which is the amount of the increment?

Inc(N, I) // to increment N by I.
Dec(N, D) // to decrement N by D.

Now I think these are for people who start using Delphi after using other languages. Personally I prefer:

N := N + 1;
N := N - 1;
N := N + I;
N := N - D;

which generates exactly the same code as Inc and Dec do, with equivalent optimizations.

Don’t forget about Pred and Succ, which when applied to integers returns the value one less and one greater without changing the original value. And you can string them, e.g.

Pred(Pred(Pred(N)));

NGLN points out it is possible to omit the parameter list of routines that are declared in the interface section. For functions it is even possible to omit the result type, which leads to weird looking implementations like:

function GetText(var A: Integer; const B: Char; C: Word = 0): String;

implementation

function GetText;
begin
  Result := 'Where am I going?';
end;

Obviously, this does not apply to overloaded routines. 😉

Sometimes when someone else’s code passes by, this is still surprising. Users would have maintenance reasons.


Rudy Velthuis points out that there is a calling convention called “winapi” which (at the moment, at least) is completely identical to “stdcall”?

Example:

function CryptReleaseContext(hProv: HCRYPTPROV; dwFlags: DWORD): BOOL; winapi;

This is fully equivalent to:

function CryptReleaseContext(hProv: HCRYPTPROV; dwFlags: DWORD): BOOL; stdcall;

lkessler always seems to forget about Method Overloading. Multiple routines can share the same name. The number of parameters and type of each parameter determine which will be called.

e.g.:

Function Multiply (A, B: integer): integer; overload;
Function Multiply (A, B: double): double; overload;

Early Delphi users might not know about this one because it was added in Delphi 4.

See: http://www.delphibasics.co.uk/RTL.asp?Name=Overload

Also there is a nice list of new Delphi language features added since Delphi 7, along with good examples of each at: http://edn.embarcadero.com/article/34324

It includes:

  • Inlining
  • Operator Overloading
  • Class Helpers
  • Strict Private
  • Strict Protected
  • Records with Methods
  • Class abstract
  • Class sealed
  • Class const
  • Class type
  • Class var
  • Class property
  • Nested classes
  • Final methods
  • Sealed methods
  • Static class methods
  • For-in loop

Jørn E. Angeltveit point out that the ; is used to separate statements, not end statements, so you actually don’t need the last ; before end:

procedure DoNothing;
begin
  Inc(i);
  Dec(i)
end;

It is more convenient to add statements and move statements when they all end with the ;, so I definitely wouldn’t recommend to implement this a new practice at the workplace 🙂


What else should be on the list?

17 replies on “Hidden features in the Delphi Object Pascal language”

Great article Jim, I hope it’s not deleted from SO, but you’re doing it right by rescuing the content.

One of the things worth mentioning as “hidden feature” is the untyped parameters, I’m sure there’s lot of people are not aware of:

procedure MyProc(var X);

On other affairs, in WordPress, inside blocks you don’t use the & syntax, since it is just “translated” into a pre html block.

Other thing is I was trying to post as a wordpress.com user, but I got “invalid security token” error message twice, and I had to re-write my comment twice

I just made a post a couple days ago about a hidden (or at least not particularly obvious or well-known) feature of the language: Any operator overload can return a value of an arbitrary type, even something like = or >, which you would expect to only return a boolean. There are a bunch of interesting things that can be done with this knowledge.

Mason, I will not call “interesting”, weird things like this:

var
I, A, B: Integer;
begin
A := 10;
B := 20;
I := A > B; //I now is 30, because the > operator really sum the opperands.
if A + B then
showMessage(‘and the + operator compares for inequality’);
end;

@jachguate: I wouldn’t call that “interesting” either. But I also wouldn’t call it “possible”. Can you actually create that functionality? AFAIK there’s no mechanism that will allow you to redefine baked-in operators on Integer or other fundamental types.

When I was working with a Pascal variant language the semi-colon was described as being used to indicate the beginning of a new statement. I was already used to putting in the ‘normal’ place but thinking about the semi-colon that way started to make sense on why you can omit it.

I’ve seen your example of “property Foo: TFoo read FFoo implements IFoo” in Marco Cantu’s Mastering Delphi 7 book. It is called Delegation there 🙂
TMyJumper = class (TInterfacedObject, IJumper)
private
fJumpImpl: TJumperImpl;
public
constructor Create;
property Jumper: TJumperImpl
read fJumpImpl implements IJumper;
destructor Destroy; override;
end;
See http://code.marcocantu.com/trac/marcocantu_marco-delphi-books/browser/masteringdelphi7/02/IntfDemo/WalkIntf.pas#

What about class operator overloading for classes (for non-NEXTGEN applications)?

You can descend a class, which members implements interfaces not directly from TInterfacedObject, moving this dependency into implementer class:

ITestable = interface
[‘{9D0AFE29-A6DD-420D-8AAE-ED19996B207D}’]
procedure Test;
end;

TTestableImpl = class(TInterfacedObject)
protected
procedure Test;
end;

TMyTestClass = class(TObject, ITestable)
private
FTestableImpl: TTestableImpl;
public
property TestableImpl: TTestableImpl read FTestableImpl implements ITestable;
end;

If you want to protect that SO post against deletion from passerby reviewers, try to ask for lock (maybe by flagging the post with the proper comment). There are many protected “hidden feature” questions, so why not also our Delphi one… Btw., this post was deleted by the same moderator at the same time when I was fighting to save “hidden features of Delphi IDE” (http://meta.stackoverflow.com/q/222285/179541). Quite a strange step though. Today, when I noticed that, I’ve asked for undeletion with moderator attention flag and Brad Larson undeleted it for us again. But without a lock, so it can be deleted again. Anyway, thanks for saving such a useful content!

Comments are closed.