Joe White’s Blog

Life, .NET, and Cats


What’s New in the Delphi Compiler?

Here’s Danny’s session, “What’s New in the Delphi Compiler”. At this point, I am actually caught up on my conference blogging. (Caught up on the first day. Will wonders never cease?)

What’s New in the Delphi Compiler

  • Major Win32 compiler work
    • Records with Methods
    • Operator Overloading
    • Class vars (per-type global storage)
    • Unit initialization consolidation
      • Large app, lots of units, lots of initialization -> loaded lots of pages from disk to run all those initialization sections.
      • When the linker does smart linking and assigning addresses, now it puts all those initializations together in one clump of code pages. Result: faster startup (on the order of 2-5%), and significant reduction in working set.
      • Next step is to put them in a separate segment, so they can be purged from the working set after startup. Not done yet.
      • Finalizations are also clumped together.
    • Inline-able magic functions (string Length(), etc.)
  • Minor .NET compiler work
    • Minor bug fixes, metadata improvements
  • .NET Compact Frameworks Enablement
    • Soften error checking for missing CLR stuff
    • Beef up class helpers

Records with Methods

type
  TBlock = record
    procedure Foo(I: Integer);
    function Bar: TBlock;
  private
    Data: Integer;
  public
    property Color: Integer …
  end;
  • In old-style objects, virtual methods were optional, so the VMT could be at a different offset in different types (if it was there at all). Difficult to work with.
  • In the Delphi language, “class” is always a reference type, for simplicity.
  • Value types: If they’re small, allocating them is fast.
  • Yes, you can reference the type within itself (see the declaration of Bar, above).
  • Private, protected, public. Probably has strict private and strict protected as well.
  • No inheritance. (So protected really doesn’t mean anything. Maybe it isn’t there after all.)
  • Default scope is public.
  • Can implement interfaces in .NET, but not in Win32
  • No published. Records have no VMT so they can’t have RTTI.
  • Can still have variant sections in the record, but they have to be at the end. May not be able to put visibility specifiers after you’ve started a variant section. Cannot put methods inside a variant section.
  • Assigning the record will copy everything regardless of visibility.
  • Note: if you put compiler-managed types in a record (string, interface, dynamic array, Variant), the compiler will generate try..finally code all over the place for you. (This is the same rules as before.)

Operator Overloading (Win32)

  • Requires value semantics. “A + B” must return a new instance. (Otherwise, who’s going to clean them up?)
  • Supported on record types only (see previous point)
  • Same syntax & rules as Delphi .NET
    • class operator Add(A, B: TQuark): TQuark;
    • class operator Add(A: TQuark; B: Byte): TQuark;
    • class operator Implicit(A: Integer): TQuark;
    • class operator Explicit(A: TQuark): Integer;
    • class operator Explicit(A: TQuark): string;
  • Implicitly overloaded, so you don’t have to use the “overload;” directive.
  • Can’t define new operators, but you can override all of the standard ones (except assignment and pointer dereferencing).
  • If you want to support all the different integer types, you have to do it yourself.
  • Commutativity is not assumed. So if you want both TQuark + Byte and Byte + TQuark, you have to define it. (Not a big deal – have one call the other, and get it inlined.)
  • Operator Explicit is the only place you’re allowed to overload on result type.
  • If TFoo defines Add(TFoo, TBar), and TBar defines Add(TFoo, TBar), the compiler will pick one. Don’t do this.
  • Implicit conversion happens when:
    • A := B;
    • Passing parameters
    • Don’t define an implicit conversion if you will lose information.
    • Will not do long-trip conversions. If A can be implicitly converted to B, and B to C, and you try to go straight from A to C, Delphi will say “Bad programmer!”
  • Explicit is for explicit casts, like TFoo(5), or Integer(MyFoo).
    • These are allowed to lose data, e.g., going from a LongInt to a Byte.
  • If two types both define the same implicit or explicit conversion (like TFoo to TBar), you will get a compiler error (ambiguous overload, or some such) at the point where you try to do the cast.
  • You cannot call TQuark.Add directly. It doesn’t exist.
  • Operators are implicitly static.
  • WriteLn(Q) uses Explicit(Quark): string
  • If you do a hard typecast on something that supports that as an implicit typecast, it’ll work. You don’t have to declare the same thing as both implicit and explicit.
  • Cast operators: Implicit, Explicit
  • Unary: Positive, Negative, Inc, Dec, LogicalNot, BitwiseNot, Trunc, Round
  • Comparison: Equal, NotEqual, GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual
  • Binary: Add, Subtract, Multiply, Divide, IntDivide, Modulus, ShiftLeft, ShiftRight, LogicalAnd, LogicalOr, LogicalXor, BitwiseAnd, BitwiseOr, BitwiseXor
  • If you define both LogicalOr and BinaryOr, the compiler will pick one. Don’t do that.
  • You can have an operator called Divide and a method called Divide. They won’t collide.
  • Operators should always create and return a new value, not modify the inputs. (Yes, this applies to operator Inc and Dec as well.)

Operator Selection

  • Expression: A + B
  • Types: TA, TB
  • Add operator is selected from the Add operators on TA and TB only, not from other classes. (Again, it’s not automatically transitive.)
  • If TA is convertible from TB, but not the other way around, TA is considered narrower, or more specific. This affects overloaded method calls.

Class vars

  • Global storage for a field within your type
  • Descendants share ancestor’s class vars
    • Not separate storage for each derived type
TMyClass = class
private
  class var SharedStuff: Integer;
public
  ...
end;
  • Cannot initialize these in Win32, yet. (No class constructors in Win32.) But you could initialize it from a unit initialization section.
  • Accessible from class functions
  • Same default initialization rules as globals: initialized to zero.
  • “class var” starts a new section. So do “var” and “type”. (”Var” and “class var” are there because of nested types in Delphi 2005 – “type” introduces a section, so you need “var” to get back out of that mode.)
  • Can have class constants as well (but not typed class constants).

Roadmap

  • These are objectives, not guaranteed feature lists
  • “Highlander” (calendar 2006)
    • Full .NET 2.0 support & integration
    • Delphi generics, class fragments, and more
    • Full .NET Compact Framework support, including VCL.NET for CF
    • Support .NET 2.0 64-bit app development
  • “Delphi Longhorn” (not the actual codename) (sometime after Highlander)
    • Win32 & .NET development for Windows Vista OS
    • Avalon (WPF)
  • Delphi Win64
    • Closest logical evolution of Win32
    • Same shortcomings as Win32 (DLLs, APIs, security)
    • Unicode VCL
    • Company green light, just needs time & resources

2 Responses to “What’s New in the Delphi Compiler?”

  1. Peter Says:

    Operator Overloading (Win32)

    Supported on record types only (see previous point)

    :-((((((((((((((((((((((((((

    …and classes????

  2. Joe White Says:

    Why would you want it on classes? When you’re overloading things like +, you really want value semantics anyway.

    The primary reason you can’t use it on classes is that, when you do A + B, it should return a new instance, C. Now who’s responsible for freeing it? The semantics get really murky there.

    There’s also the fact that Microsoft’s guidelines for operator overloading pretty much say, "Don’t do it for classes." See:

    http://www.gotdotnet.com/team/fxcop/Docs/Rules/Design/DoNotOverrideOperatorEqualsOnReferenceTypes.html

    http://www.gotdotnet.com/team/fxcop/Docs/Rules/DesignRules/AddAndSubNoEqualsOp.html

    …and then apply the transitive property to those two rules. If you overload + and -, you should also overload =, which you shouldn’t do on reference types.

    If you *really* want both operator overloading and classes for some reason, you could probably accomplish that by making a record type (with operator overloading) that wraps an interface reference (so you can do class-type stuff like inheritance).

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>


Joe White's Blog copyright © 2004-2008. Portions of the site layout use Yahoo! YUI Reset, Fonts, and Grids.
Proudly powered by WordPress. Entries (RSS) and Comments (RSS).