Wednesday, January 19, 2005

FastCoder's 2004 New Year's Speech

The fine FastCoder hackers residing over in the borland.public.delphi.language.basm newsgroup have summarised their activity in the past year. The highlights are:

  • John O'Harrow is the contributor of the most and best FastCode challenge entries (winning a Delphi 2005 Pro)
  • Three FastCode routines were included in the updated Win32 RTL in Delphi 2005 (CompareText, Int64Div and FillChar)
  • 16 challenges were completed
  • The best AnsiStringReplace routine is now some 17 times (!!!) faster than the Delphi RTL StringReplace function
  • A new major challenge is writing an improved memory manager (faster, less fragmentation, better multi-CPU performance, using less memory)
  • A 64-bit version of Delphi is desired

Read the whole speech here. Keep up the good work, FastCoders!

Tuesday, December 28, 2004

Delphi vs C#: Destructors

Delphi's implementation of destructors is very different from C#'s. This means that if you are translating C# code samples to Delphi, you have to be careful with how you convert C# destructors. A question from Ray in the delphi.rtl.dotnet newsgroup illustrates this problem:

"Subject: Garbage collector bug in Delphi.NET but not C#?
Hi there
In testing the Garbage collection in Delphi.NET I found the following.
Delphi.NET code

//******************** 
type
TDemo = class
public
class var Instances: integer;
constructor Create; virtual;
destructor Destroy; override;
end;
//futher down
procedure TWinForm.Button2_Click(sender: System.Object; e: System.EventArgs);
var
x: Integer;
a: TDemo;
begin
Text := 'Running';
for x := 1 to 100000 do begin
a := TDemo.Create;
a.Free;
end;
end;

procedure TWinForm.Timer1_Tick(sender: System.Object; e: System.EventArgs);
begin
Text := TDemo.Instances.ToString;
end;

procedure TWinForm.Button1_Click(sender: System.Object; e: System.EventArgs);
var
x: Integer;
a: TDemo;
begin
for x := 1 to 100000 do begin
a := TDemo.Create;
end;
end;

{ TDemo }

constructor TDemo.Create;
begin
inherited;
Inc(Instances);
end;

destructor TDemo.Destroy;
begin
Dec(Instances);
inherited;
end;
//********************

and the C#


//********************
  public class Demo
  {
    public static long Instances;
    public Demo()
    {
            Instances += 1;
    }
    ~Demo()
    {
       Instances--;
    }
  }
//Further down
  private void button1_Click(object sender, System.EventArgs e)
  {
    int Counter;
    Demo aDemo;
    for (Counter = 0; Counter < 100000; Counter++)
    {
      aDemo = new Demo();
    }
  }
  private void timer1_Tick(object sender, System.EventArgs e)
  {
    Text = Demo.Instances.ToString();
  }
//********************

Now the issue I have is with C# it will have 100 000 classes and then a few seconds later 37125 then click button and it's 2500 etc. Works like the help says...


BUT Delphi is "buggy". Button1 creates 100 000 and does NOT free even after multiple clicks, however button2 with the .Free frees instantly. So it works like Win32. Surely this is a bug (Not that I'm complaining I'd rather it free up memory when I say so).


Am I missing something?


Regards Roy"


This is not a bug - a Delphi destructor is not the same as a C# destructor.


A Delphi destructor implements the IDisposable pattern, while a C# destructor overrides the Finalize method of System.Object (a very rarely recommended practice). Look at the generated IL code from both compilers, and you will see the difference.


To make the comparison relevant, either change the Delphi code to override the Finalize method or change the C# code to implement the IDisposable interface. FWIW, the new C++/CLI standard implements C++ destructors as IDisposable implementations too. C# destructors are a mistake, IMO. Don't use them unless you know exactly what you are doing.


This triggered a follow-up question from Ray:



"I got the C# code from a MSCD.NET CD, and according to the demos / trainer material this is recommended? Besides VB.NET worked the same as C# so does "C# destructors are a mistake" hold true for VB.NET?


http://www.delphi.about.com/od/delphifornet/a/aa060104a.htm


"Every class in the .NET Framework inherits a method called Finalize. The bad news is that the GC calls the Finalize method (and therefore if overridden it should be protected) when the memory for the object is about to be freed. Since the method is called by the garbage collector, you have no control over when it is called.


The good news is that in Delphi for .NET, all objects implicitly implement IDisposable and redirect calls to Dispose to the Destroy destructor. This means that you do not need to implement Dispose yourself ... you can safely continue freeing resources (for objects/classes you develop) in the object's destructor "Destroy" method."


The part that threw me off was "you have no control over when it is called."


That's one of the reasons Finalize is generally not recommended. Another is that objects are kept alive much longer than needed.


Finalize is generally only needed for cleaning up unmanaged resources like file and window handles - and that should in 99% of the time be taken care of by small low-level wrapper classes defined in the .NET framework.


99% of the time you do not want to implement C# destructors in application-level code.


99% of the time(1) you do want to implement IDisposable in application-level code. Writing Delphi destructors makes this easy.


This artible by Brian Long is recommended reading:
http://bdn.borland.com/article/0,1410,29365,00.html


(1) The reason for this is that while finalizers are singular and automatically called by the GC (only the class holding references to unmanaged resource handles need finalizers), IDisposable requires a cascading implementation in wrapper objects. For instance, if a class A is implemented in terms of (by having a private reference to) a class B, and class B implements the IDisposable interface, the wrapping class A should also implement the IDisposable interface. This even includes cases where the implementation of A or B might change in the future to implement IDisposable.

Tuesday, November 16, 2004

Object-to-interface casts

There are several ways to check if an object reference implements an interface or not - but there are some platform differences. The as-cast works (almost) identically in both Win32 and .NET.

var 
MyObject: TMyObject;
MyInterface: IMyInterface;
begin
// ...
MyInterface := MyObject as IMyInterface; // may raise EInvalidCast
MyInterface.Foo;
end;

The platform difference is that on Win32, the declared object type must implement the IInterface (or IUnknown) interface (as TInterfaceObject does, for instance), while in .NET any object type will do. If the cast fails, an exception will be raised. This is often undesirable - often you need to treat objects differently depending on if they implement a specific interface or not, and handling exceptions is too slow and cumbersome. On .NET you can cast from any object to any interface, using a hard-cast syntax. If the cast fails, nil is returned instead.

var 
MyObject: TMyObject;
MyInterface: IMyInterface;
begin
...
MyInterface := IMyInterface(MyObject); // .NET specific
if Assigned(MyInterface) then
MyInterface.Foo;
end;

Currently, the Win32 compiler does not support this cast in a generic way. It does support it in the specific case when the cast can be determined to be valid at compile-time. This can be done when the declared object type statically implements the given interface. If this is not the case, the cast fails with a compile-time error; [Error]: Incompatible types: 'IMyInterface' and 'TInterfacedObject' To check if an object supports an interface without raising exceptions, you can first cast it to IInterface then call the QueryInterface method. This only exists on Win32:

 Intf := IInterface(MyObject); 
if Intf.QueryInterface(IMyInterface, MyInteface) = 0 then
MyInterface.Foo;

The Supports routine in the SysUtils unit gives is a more convenient and cross-platform way of doing the same thing:

 if Supports(MyObject,IMyInterface, MyInteface) then 
MyInterface.Foo;

Supports is also available on .NET, but it is implemented in a way that makes it much slower than using the (currently) .NET-specific hard-cast. This is because the .NET version is implemented in terms of the new 'type of interface' construct:

type 
TInterfaceRef = type of interface;
...
function Supports(const Instance: TObject; const IID: TInterfaceRef; out Intf): Boolean;
begin
Result := Instance is IID;
if Result then
Intf := Instance as IID;
end;

The 'type of interface' construct is pretty neat, actually. It allows you to pass any interface-type as a parameter to a method. This is used instead of a TGUID as an identifier or handle to the given interface. The Supports function itself compiles into the following IL:

.method public hidebysig static bool Supports(object Instance, [mscorlib]System.RuntimeTypeHandle IID, object& Intf) cil managed 
{
// Code Size: 50 byte(s)
.maxstack 3
.locals (
bool flag1,
[mscorlib]System.Type type1)
L_0000: ldarg.1
L_0001: call [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle([mscorlib]System.RuntimeTypeHandle)
L_0006: ldarg.0
L_0007: callvirt instance bool [mscorlib]System.Type::IsInstanceOfType(object)
L_000c: stloc.0
L_000d: ldloc.0
L_000e: brfalse.s L_0030
L_0010: ldarg.2
L_0011: ldarg.1
L_0012: call [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle([mscorlib]System.RuntimeTypeHandle)
L_0017: stloc.1
L_0018: ldloc.1
L_0019: ldarg.0
L_001a: callvirt instance bool [mscorlib]System.Type::IsInstanceOfType(object)
L_001f: brtrue.s L_0029
L_0021: ldarg.0
L_0022: ldloc.1
L_0023: call object Borland.Delphi.Units.System::@CreateCastException(object, [mscorlib]System.Type)
L_0028: throw
L_0029: ldarg.0
L_002a: castclass object
L_002f: stind.ref
L_0030: ldloc.0
L_0031: ret
}

Quite a bit of code!


With a little help from Reflector, I've found that it corresponds to something like this in Delphi code:

function Supports(Instance: TObject; IID: RuntimeTypeHandle; out Intf: TObject): boolean; 
var
InterfaceType: System.Type;
begin
Result := System.Type.GetTypeFromHandle(IID).IsInstanceOfType(Instance);
if Result then
begin
InterfaceType := System.Type.GetTypeFromHandle(IID);
if (not InterfaceType.IsInstanceOfType(Instance)) then
raise EInvalidCast.Create(SInvalidCast);
Intf := Instance;
end;
end;

Notice that the code is a little redundant. The precence of both the is-check and the as-check makes the compiler emit calls to GetTypeFromHandle and IsInstanceOfType twice each. The exception will never be raised in this method. So there is a little room for improvement here. I think that passing 'type of interface' parameters as System.Type instead of RuntimeTypeHandle would also make it a little more efficient - in most (all?) cases the call site has a Type reference anyway and first has to convert it into a RuntimeTypeHandle. The site calling Supports yields this IL:

   ldloc.1 
ldtoken Obj2IntfCastNET.IMyInterface
call [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle([mscorlib]System.RuntimeTypeHandle)
pop
ldtoken Obj2IntfCastNET.IMyInterface
ldloca.s obj2
call bool Borland.Vcl.Units.SysUtils::Supports(object, [mscorlib]System.RuntimeTypeHandle, object&)
stloc.0


By contrast, performing the same operation by using the object-to-interface hard-cast, gives this very simple and efficient IL:


    ldloc.s obj2
   isinst Obj2IntfCastNET.IMyInterface
   stloc.2


Can you guess which is faster? No prizes for this one! So you can use the cross-platform Supports function - which is fairly efficient in Win32, but relatively slow in .NET, or the .NET platform specific and efficient hard-cast. Most of the time, the slow .NET version of Supports does not really matter, but for some performance critical points, you might want to use conditional compilation to select the best solution for each platform, like this:

{$IFDEF WIN32} 
if Supports(MyObject,IMyInterface, MyInterface) then
{$ENDIF}
{$IFDEF CLR}
MyInterface := IMyInterface(MyObject);
if Assigned(MyInterface) then
{$ENDIF}
MyInterface.Foo;

I hope that a future version of the Win32 compiler can be extended to support hard-casts from object-to-interface with the same semantics as on .NET. The cast should return nil if the object does not support the interface (yes, this has been reported to Borland). In .NET you can also use the 'is' operator to check if an object implements an interface or not. This is not currently supported in Win32.

 if MyObject is IMyInterface then 
Writeln('Yup');

Friday, November 12, 2004

Machine Code Hacking

I'm not shy from performing the occasional hack, and feel comfortable working in the CPU view of the debugger. Microsoft hacker Raymend Chen seems to be in another league however. He claims he never uses source level debugging (its too mucked up by the optimizer anyway) and here he gives some tips on how to patch machine code bytes while debugging to make the debuggee do what you want. Useful for those low-level debugging sessions ;).

Tuesday, November 09, 2004

Rocket Scientist wanted!

Our company are looking for the best Delphi and C++ programmers out there. From our website: "Our highly qualified team of developers are looking for new colleagues. If you are an experienced developer looking for a challenging position in an informal organization we would very much like to hear from you." The details about the positions are available here (in Norwegian): "Rocket Scientist" - Borland Delphi / C/C++ So send us an email with your resumé - or tips your favorite Delphi or C++ guru... :) Updated: The job advert is now available in English: http://www.infront.no/pdf/jobad_programmer.pdf

Monday, November 08, 2004

Delphi 2005 Reviewer's Guide

Borland has just made a very comprehensive review guide for Delphi 2005 available. It is written by Cary Jensen and can be downloaded here: http://www.borland.com/products/white_papers/ pdf/delphi_2005_reviewers_guide.pdf If you wonder what's new and how the new features look like, check it out.

Interfaces - benfits and platform differences

Interfaces is a very powerful tool that can improve the quality of your code, if used properly. Interfaces can give the following benefits:

  • Reduced coupling between components
  • Strong encapsulation
  • High extensibility
  • Easy substitutability
  • Run-time discovery of object capabilities

Under the hood, interfaces are implemented very differently in .NET and Win32. Win32 interfaces follow the COM model, with an IUknown base interface that provides basic services for reference counted lifetimes and interface support querying.

A Win32 interface declaration needs a GUID to enable as-casts (or QueryInterface or Supports calls). GUIDs are not needed in .NET - they can optionally be used to expose interfaces to COM with a specific GUID. To generate a GUID in the editor use the Shift+Ctrl+G keyboard shortcut.

type 
IMyInterface = interface
['{6141D774-34AD-4E11-AB16-DD74EFE793F5}']
procedure Foo;
end;

.NET interfaces do away with reference counting and instead relies on the garbage collection mechanism that all object references enjoy. There is no base-interface that all other interfaces inherit from.


Instead of QueryInterface, IL instructions like castclass and isclass and methods of the Type class are used. At runtime, the reference value of an interface variable is identical to the object reference value that implements the interface. The only difference is the type of the variable and how the JIT compiler dispatches method calls on the interface reference. More on casting to and from interfaces differences shortly.



Copyright © 2004-2007 by Hallvard Vassbotn