views:

1086

answers:

10

With the introduction of Delphi 2009, a lot of features are added to the Object Pascal language. Almost anybody knows about generics and closures, but there are more, and not all of them are documented (or at least hard to find).

What are the lesser known language constructs of OP that you know about?

+13  A: 

Exit

Within functions, Exit can have a parameter:

function IsMagic(const AValue: Integer): Boolean;
begin
  if AValue<0 then Exit(False);

  ...
end;

Deprecated

The deprecated hinting directive can have an optional message:

const
  cDeviceCRT = 12 deprecated 'Why not use a flatscreen';

The message is shown with the deprecated warning. And it must be a string literal and no const expression. The other hinting directives (platform, library, experimental) are excluded.

Gamecat
Iirc, the deprecated message was already scheduled to work in Delphi 2005... Pity it took so long, but it's nice to have it now.
PatrickvL
I did not know about the parameter for exit. It's great, something I have been wishing for, for many years now...
mghie
what exactly do you mean by "excluded"? so the same does not work for "experimental" et al?
Oliver Giesen
Yup that is what I meant.
Gamecat
deprecated, platform also work for whole units.
Marco van de Voort
+8  A: 

{$pointermath ON} to do pointer arithmetic.

This can be used in either of two ways:

  1. Types or aliases defined while {$POINTERMATH ON} is in effect will have C-like pointer semantics;

  2. Expressions parsed while {$POINTERMATH ON} is in effect may use pointers in a C-like fashion.

By C-like, we mean:

  • Indexing like an array
  • Addition and subtraction of integers to move the pointer along (or back), with a stride equal to the size of the pointed-to type
  • Difference of two pointers to get the number of elements between the two pointers
François
And what happens with {$pointermath OFF}? Is Inc(p) no longer possible then?
mghie
Inc(x) when x is a pointer type is always possible. However adding and subtracting arbitrary integers, arbitrary indexing, and subtraction to find an integer difference are unique to {$POINTERMATH ON}.
Barry Kelly
Very interesting. I recently ported an implementation of the Levenberg-Marquardt algorithm from C to Delphi, this would have been much easier with the C-like pointer semantics. That's a big +1 for buying D2009.
mghie
I bought D2009 last week, mainly because this makes porting FPC code easier. If you now also implement pointer increment on the "pointer" type, Delphi is almost FPC compatible again. IOW untyped pointer is treated as "pbyte" for increment/decrement purposes
Marco van de Voort
+3  A: 

Old-style "object" types still exist, and even support inheritance, visibility modifiers and virtual/overrides.

Here an example :

type BaseType = object
protected
  FValue: Integer;
public
  procedure Initialize(const aValue: Integer); virtual;
end;

type ExtensionType = object(BaseType)
private
  FExtra: Integer;
public
  procedure Initialize(const aValue: Integer); override;
end;

You do need to be aware of a few facts about this :

  • support for this might be dropped in the future (it's been deprecated since Delphi 3, although you can still use this in Delphi 2009)
  • just like records, instances of these types are stack-allocated
  • unlike records, "object" instances are not finalized

That being said, I do think it's an nice alternative to records (which don't support inheritance), and classes (which aren't stack-managed).

PatrickvL
Initialization and finalization are important if the object is to hold any compiler-managed types, like strings, interfaces, or dynamic arrays. See this link for details.http://groups.google.com/group/comp.lang.pascal.delphi.misc/msg/2176ea3300f2dfb9
Rob Kennedy
Objects are around from the Borland Pascal time (whas it 5, 6 or 7?). But although you can still use them, it is discouraged, because classes have a lot more functionality.
Gamecat
Classes have overhead, and usually that is the reason for TP objects. The records with methods in them from D2006 onward are better substitutes.
Marco van de Voort
+3  A: 

The fact that WinAPI wrappers have changed from -A (Ansi) to -W (Wide) implementations. Together with the change of String to UnicodeString and Char to WideChar, this has been an almost completely transparent change for a lot of code using these. The benefit is: no more hidden internal translations to Ansi, improving speed and compatibility.

PatrickvL
+8  A: 

Don't forget about {$SCOPEDENUMS ON}: enumerations defined while this is in effect will not have their values added to the unit / program scope directly, but will have to be explicitly qualified with the enumeration name, just like in C#.

FWIW, (almost) all enumeration values can be explicitly qualified by enumeration name (the main exception I'm aware of is Boolean), like this:

type
  TMyBool = (T, F);
begin
  Writeln(Ord(TMyBool.T));
end.
Barry Kelly
That's a nice one!
PatrickvL
Can you clarify, please? I can't tell from your wording whether the syntax you describe requires $SCOPEDENUMS ON or whether it's always allowed. I've never seen it before.
Rob Kennedy
<EnumName>.<EnumValue> scoping was not allowed before .NET (Delphi 8), AFAIK - though it may have come in on the Win32 side a little later. However, making it so that you *must* use <EnumName>.<EnumValue>, i.e. just like .NET, requires that you use $SCOPEDENUMS ON.
Barry Kelly
That might be the first feature from .NET that I actually like.
Marco van de Voort
+5  A: 

Six Hidden Features of Delphi 2009

+4  A: 

TextHint support for edits and combo boxes in XP and later. Windows TextHint support for combo boxes was officially introduced in Vista. Delphi is doing some trickery behind the scenes on XP.

Bruce McGee
+2  A: 

I've been using Delphi since version 3 and only just today discovered threadvar

It lets you do Thread Local Storage by using some compiler magic

Will probably never use it mind you!

Jamie
I've used it. It's a great trick, if you can use them responsibly. (Threadvars are basically global variables, so you have to be careful with them.)
Mason Wheeler
A: 

Another nice one. Use the constructor constraint with generics:

type
  TMyClass<T: TMyOtherClass, constructor> = class
  public
    function NewOther: T;
  end;

function TMyClass.NewOther: T;
begin
  Result := T.Create;
end;

This is not possible without the constructor constraint.

Gamecat
A: 

If you have D2009 then you can probably download the free PDF of Marco Cantu 'Delphi 2009 Handbook'. It's on the Codegear site for registered users, but I bought a copy as well. He lifts the lid on loads of low-level D2009 stuff. You can read more about it here

Brian Frost