Archive

Archive for December, 2008

Delphi and the Integer data types

December 26th, 2008 alex No comments

There’s a lot of discussions on CodeGear newsgroups lately regarding the Integer data types and 64 bit support. Just wanted to clarify some points for people waiting for the 64 bit release of RAD Studio (due somewhere in 2010).

The “fundamental” Integer types (the ones that have constant sizes on all platforms) are:

  • Byte (1 Byte, Unsigned)
  • UInt8 (alias for Byte)
  • ShortInt (1 Byte, Signed)
  • Int8 (alias for ShortInt)
  • Word (2 Bytes, Unsigned)
  • UInt16 (alias for Word)
  • SmallInt (2 Bytes, Signed)
  • Int16 (alias for SmallInt)
  • LongWord (4 Bytes, Unsigned)
  • UInt32 (alias for LongWord)
  • LongInt (4 Bytes, Signed)
  • Int32 (alias for LongInt)
  • UInt64 (8 Bytes, Unsigned)
  • Int64 (8 Bytes, Signed)

Previously listed Integer types are fixed in size — meaning that no matter what OS/CPU you’re running on, these types will have the same size.

CPU specific Integer types are listed below:

  • NativeUInt (Unsigned, depends on CPU register size)
  • NativeInt (Signed, depends on CPU register size)

Note that the sizes of this Integer types actually depend on the “target architecture” you’re going to compile you program for. So if you are targeting Windows for 64 bit you will get 8 Byte wide native Integers. If you target the 32 bit Windows and you’re running your application on 64 bit Windows, NativeInt will still be 4 bytes wide.

And at last, the “generic” data types:

  • Cardinal (Unsigned, depends on OS definition of Integer)
  • Integer (Signed, depends on OS definition of Integer)

Yes, it might be confusing, but Integer and Cardinal are not CPU specific, but rather OS specific. In the case of Windows for 64 bit, the “int” is still 4 Bytes wide.

So what happens if you want to transition your Delphi application to 64 bit Windows? Not much really. Few things will actually break, the most usual culprits will be:

  • Windows API calls. Most Windows APIs that require handles can break down for you if you forĀ  instance consider a HWND to be a Cardinal. HWND will be 64 bit while Cardinal will stay 32 bit wide. The same applies to a lot of other Windows functions.
  • Casting a Pointer to an Integer and back. Pointer is actually the same size as the NativeInt type so be sure to fix these issues in your code. Just replace Integer with NativeInt. Many developers cast a Pointer to an Integer to perform some arithmetic so that would be a pretty common case. I hope the compiler guys will add a warning if you cast between Integer and Pointer data types.
  • The Tag property. I know a lot of people rely on the Tag property of VCL components to keep some state information in the GUI objects. Because the Tag property is currently defined as an Integer and you need to store an Object there, casting is performed — which brings us to the second point. But no need to worry here as the Tag property will become a NativeInt so nothing will break.
Categories: Programming

Delphi Generics: constructor restriction

December 25th, 2008 alex No comments

As promised in the previous post “Delphi: Default parameterless constructor” I will now try to create a new generic class that accepts a type parameter that has a “constructor” restriction (must have a default public parameterless constructor).

Let’s start off with a simple example:

type
  TMyClass = class
  end;

  TMyGenericClass<T: constructor> = class
  end;

var
  GenObj: TMyGenericClass<TMyClass>;

begin
end.

This is a legitimate example that will compile. TMyClass inherits the default parameterless constructor from TObject. Even though this is not the result that you would expect in other languages, it’s still somehow correct.

Moving further, let’s check what happens if we declare a private default constructor:

type
  TMyClass = class
  private
    constructor Create();
  end;

  TMyGenericClass<T: constructor> = class
  end;

{ TMyClass }
constructor TMyClass.Create();
begin
  WriteLn('TMyClass.Create()');
end;

var
  GenObj: TMyGenericClass<TMyClass>;

begin
end.

And here we will get a compile error. The requirement that TMyClass has a public parameterless constructor is not satisfied!

But don’t be too happy just yet! The next example cracks it again:

type
  TMyClass = class
  public
    constructor Create(const AParam: String);
  end;

  TMyGenericClass<T: constructor> = class
  end;

{ TMyClass }
constructor TMyClass.Create(const AParam: String);
begin
  WriteLn('TMyClass.Create()');
end;

var
  GenObj: TMyGenericClass<TMyClass>;

begin
end.

It seems that the default constructor is yet again found — the one inherited from TObject.

The last one (I promise!) follows:

type
  TMyClass = class
  private
    constructor Create(); overload;
  public
    constructor Create(const AParam: String); overload;
  end;

  TMyGenericClass<T: constructor> = class
  end;

{ TMyClass }
constructor TMyClass.Create(const AParam: String);
begin
  WriteLn('TMyClass.Create()');
end;

constructor TMyClass.Create;
begin
end;

var
  GenObj: TMyGenericClass<TMyClass>;

begin
end.

Again, a compilation error is risen. We’re back on the right track.



The final conclusion to this post and the previous one is:

If you do not have/need a default public parameterless constructor in your class, you must still define a private one that would raise an Exception telling the programmer to not call it. Doing this you will ensure that your constructor is being executed and not the TObject provided one, resulting in a predictable object state. Also this will ensure that the “constructor” restriction will be enforced correctly!



~Yes, I know, Delphi sucks sometimes :)

Categories: Programming

Delphi: Default parameterless constructor

December 25th, 2008 alex 7 comments

A weird consequence of Delphi’s OOP behavior is how constructors are handled, and in particular how the default parameterless constructor is handled.

Consider the following example:

type
  TMyClass = class
  end;

var
  Obj: TMyClass;

begin
  Obj := TMyClass.Create();
  Obj.Free();
end.

This code will actually compile and run. This happens because Create() constructor is inherited from TObject base class. So far, so good (actually it’s not that good, but at least we know what happens).

Now let’s define a parameterless private constructor (hoping to hide it like in other OOP languages):

type
  TMyClass = class
  private
    constructor Create();
  end;

{ TMyClass }
constructor TMyClass.Create;
begin
end;

var
  Obj: TMyClass;

begin
  Obj := TMyClass.Create();
  Obj.Free();
end.

This will again compile and run! But now, the actual TMyClass.Create() constructor will be called even if it’s private. It seems you cannot make a private version of the default constructor … Bad!

Third try: Let’s define a constructor with parameters and see what happens then:

type
  TMyClass = class
  public
    constructor Create(const AParameter: Integer);
  end;

{ TMyClass }
constructor TMyClass.Create(const AParameter: Integer);
begin
end;

var
  Obj: TMyClass;

begin
  Obj := TMyClass.Create();
  Obj.Free();
end.

OK, now we have a compilation error: “Not enough actual parameters” for TMyClass.Create() call. Well, that’s not exactly what we wanted, but it will do for now: we got rid of the default constructor!

And the final try, suppose you want a class that has more than one constructor:

type
  TMyClass = class
  public
    constructor Create(const AParameter: Integer); overload;
    constructor Create(const AParameter: String); overload;
  end;

{ TMyClass }
constructor TMyClass.Create(const AParameter: Integer);
begin
end;

constructor TMyClass.Create(const AParameter: String);
begin
end;

var
  Obj: TMyClass;

begin
  Obj := TMyClass.Create();
  Obj.Free();
end.

Bad! — it compiles again.

It seems that no matter what I do, I can’t get rid of the default constructor! The only reasonable thing I can do is define a default constructor that just raises an Exception if it’s called.

Coming up next: Generic class restriction: “constructor”.

Categories: Programming

Help Update 1 is out!

December 21st, 2008 alex No comments

Finally, Help Update 1 for RAD Studio 2009 is out. You can read more about it here. Note that there are more fixes and improvements which were not mentioned. Even more are being planned for Help Update 2 due to come somewhere at the start of 2009

Enjoy ;)


P.S. Forgot to mention that this is the first release that contains work from the newly formed Romanian Tech Writing team.

Categories: Programming

Out vs Var parameters

December 21st, 2008 alex No comments

All Delphi developers obviously know about the var keyword, otherwise known as “by reference“. Some (although I doubt it) may not know that Delphi has an out keyword also. Both are identical in the fact that both are “by reference“, but there is a difference – var parameters are expected to carry a valid value when entering and exiting a function, and out is only expected to carry a valid value when exiting a function.

Now, to the weird stuff — consider this small example:

procedure CopyStr(const AStr: String; out AOutStr: String);
begin
  AOutStr := AStr;
end;

var
  SomeStr: String;

begin
  SomeStr := 'Hello World';
  CopyStr(SomeStr, SomeStr);
  WriteLn(SomeStr);
  ReadLn;
end.

Normally you would expect the result to be “Hello World“, as nothing basically would happen. AStr is copied to AOutStr which are references to the same variable: SomeStr. Well, if AOutStr was prefixed with a var keyword instead of out then you would have been right!

Remember that the Delphi compiler has a “contract” it must respect — All reference counted variables are initialized to “nothing” (or nil). So what happens in our case is that AOutStr is actually “a result value” and is not expected to contain a valid value when entering the function. The compiler must initialize it to nil before actually executing any code inside the function. So it clears the AOutStr string (which is also AStr) and that makes AOutStr receive an empty value from now cleared AStr parameter. The result is that SomeStr will be empty after the call to this function.

And now this begs the question: If the compiler is smart enough to figure this case out, why are the string result values considered var parameters and not out? This question is related to my previous post about the way the compiler treats the string and dynamic array result values. I guess this is because the out parameter type was introduced later, and so the compiler team was wary of breaking the way the things worked. Many pieces of software may actully depend in the fact that Result is treated like var and not being cleared out before entering the function.

Categories: Programming

Links up again

December 18th, 2008 alex No comments

After some struggle I managed to get the downloads working again.

Enjoy.

Categories: Test

Downloads are down

December 17th, 2008 alex No comments

Seems that the last update of the Download Monitor plugin I’m using in my WordPress broke down quite ugly. All the downloads were lost.

I will try to put them up and running ASAP.

Categories: Test

String results and the weird stuff

December 16th, 2008 alex No comments

There is an interesting particularity to the Delphi compiler. It relates to Strings and Dynamic Arrays. Consider the following two routines:

function DoSomeThing() : String;
begin
  Result := Result + ' World';
end;

procedure DoSomeThing2(var Result: String);
begin
  Result := Result + ' World';
end;

What is the difference between these two routines? Nothing except the syntax. In both cases Result is actually a var parameter sent to the function. So all the functions that return a string or a dynamic array are treated as procedures that have plus one parameter — the result variable.

Now consider this code:

procedure MyFunction();
var
  X: String;
begin
  X := 'Hello';
  X := DoSomeThing();
end;

You would think that X will become ” World” when in fact the result is “Hello World”. And this is correct if we consider that in fact this call “X := DoSomeThing()” will be translated to “DoSomeThing(X)“.

So the next time you’re writing a function that returns a string or a dynamic array be sure to initialize the Result to an empty string (or a nil for arrays).


One final note: In case of the main begin … end. block this behaviour changes. The compiler will actually allocate another local (invisible) variable that will receive the result and the copy that hidden variable to X so the result will be ” World”. This is probably due to optimizations.

Categories: Programming

Cool security

December 10th, 2008 alex 4 comments

This is not a Delphi post, it’s a post about stupidity! I have my laptop protected by a boot password. The cool thing is that if you press CTRL+ALT+DEL at the time when you have to enter the password, the laptop reboots and will not ask you for the password. Guess I have to remve the password … it’s useless anyway.


Note: I’m talking about Fujitsu-Siemens Amilo Pro V3505-1.

Categories: Uncategorized

Delphi 2009 Language features

December 7th, 2008 alex No comments

Check out this link — pretty much details all the new language features added in Delphi 2009.

A big thanks goes to Marco Cantu for preparing this document.

Categories: Programming