Home | Shorter Path | About Me
Home
About Me

Archive

2004

01

02

03

04

05

06

07

08

09

10

11

12

 

2005

01

02

03

04

05

06

07

08

09

10

11

12

 

2006

01

02

03

04

05

06

07

08

09

10

11

12


Danny's talk

Monday, September 13, 2004 03:31 PM

I'm live-blogging from Danny Thorpe's "What's new in the Delphi compiler" session. John Kaster had 4 hours to run through almost 200 slides. Danny has 4 slides in 1 hour - and, as he says, it's going to be tight. Oh, and live bloggers have been specifically asked to correctly spell anything we copy from the slides.

Let's move on to the technical stuff:

For..in loops

This is basically an enumeration, similar to the for each C# construct. It's no longer necessary to define an index in order to enumerate items. The enumerator class can do additional things, such as pre-fetch records to improve performance.

The elements you get back from enumeration are read-only. Write-back elements are not supported by the .NET Framework, although it might be possible (in a future version) for Win32. The compiler can take advantage of special circumstances to optimize the loop (for example, when looping over arrays).

In .NET, enumeration is based on the IEnumerable interface. In Win32, the compiler looks for a specific pattern.

Some things about enumeration: enumeration does not guarantee a specific order. Enumerators can also be transactional.

Here's how it works:

procedure Test(list: TStringList);
var
  s: string;
begin
  for s in list do
    writeln(s);
end;

There are several ways of implementing a collection supported by the for..in construct:

  • a class implementing the IEnumerable interface (for .NET only).
  • a class with a public function called GetEnumerator.
  • Compiler recognized primitive types (arrays, sets, and strings). Delphi will supports enumerating over sets, in addition to C#-like support for array enumeration.

When implementing the GetEnumerator method, you return a class implementing a specific pattern:

public
  function GetCurrent: TObject;
  function MoveNext: Boolean;
  property Current: TObject read GetCurrent;
end;

(the type returned by GetCurrent is the type being enumerated).

Multiunitnamespaces

In Delphi 8, each unit is considered a separate namespace. In Diamondback, it will be possible to include multiple units into a single namespace. The problem was how to do this without breaking the Delphi make logic.

It's important to note that there is no relationship between an assembly file name and namespaces within it. A single assemble can contain multiple namespaces, and a single namespace can contain modules from multiple assemblies (this actually lets you contribute to namespaces from someone else). The Delphi uses clause refers to namespaces, not assemblies.

The Diamondback solution uses a little trick: the rightmost name in a Delphi unit name is dropped from the namespace. For example, Borland.Vcl.Classes and Borland.Vcl.Controls will both belong to the Borland.Vcl namespace.

When using a Delphi unit, you have several options:

  • Specify the full unit name. This is how it's done today.
  • Access the entire namespace. This is only possible when linking against packages/assemblies.
  • Use a wildcard. The syntax "uses Borland.Vcl.*" will locate all units that match the pattern. Note that this could link in the entire VCL to your application. although most of that will be removed by the smart linker, the compiler still has to pull in the symbols from all of these units, which may require a lot of resources and considerably slow-down compilation. This syntax also disables initialization sections for units that are not explicitly referenced.

Global variables and procedures (placed in a per-unit class in Delphi 8) will be emitted as members of a class with the same name as the unit, placed in a module called "Units" - so global variables from Borland.Vcl.Classes will be placed in a class called Borland.Vcl.Units.Classes.

Function inlining

The idea of function inlining is to copy the code within a function into the call site for that function. When the function is small enough, this can produce a significant performance boost, because it eliminates the cost of actually calling the function. On the other hand, function inlining can cause code bloat, so it should be used with care.

A new directive, inline, tells the compiler to inline a function. Another option is to have the compiler look for inlining candidates automatically, but that can be very inefficient. Function inlining is supported in both Win32 and .NET, even though the JIT compiler already does some inlining.

The inline directive is a suggestion. The compiler may choose to ignore it if - Danny's words - "it thinks you're wrong or you're stupid." Also, the Delphi compiler is a single-pass, top-down compiler, so the function body must be seen by the compiler before calls to it can be inlined. Circular unit references will also defeat inlining. Finally, asm routines cannot be inlined.

Another restriction on inlining is that inlinable code has limited access to private or protected symbols, especially in .NET, since once the code is moved outside the class to which it belongs, it loses access to that class's private and protected symbols.

An interesting side effect of inlining is that it increases unit brittleness. If an inlined function changes, all units that use it must be recompiled - even if the function is in a unit's implementation section. In the past, changes to the implementation section had no affect on other units.

Inlining is controlled by a compiler directive: {$INLINE ON/OFF/AUTO}. The default is ON. AUTO means the compiler will examine inlinable functions.

Miscellaneous improvements

There are some code generation improvements, and some new features:

  • Unicode identifiers, with support for UTF-8 and Unicode source files.
  • Do not use Unicode identifiers in published properties or methods.
  • Improved overload discrimination.
  • Forward declarations for record types (.NET only).

Future directions

Some things considered for the future:

  • Supporting .NET 2.0, including parameterized types (generics).
  • Support for partial classes and anonymous methods - even though those are not supported by the CLR, they are implemented by C#.

Copyright 2004 Yorai Aminov