Delphi2009を体験する

今回のDelphi2009(Win32)は面白そうな機能追加が多くあり、購入を考えているので体験版をダウンロードして使ってみました。ちなみに現在持っているのはDelphi2005です。

起動時間について

Delphi2005は遅いと有名で、2006の時点で起動時間の問題は解消されています。2009の起動時間はそんなに長くなかった(おそらく2007と同じぐらい?もしくはもっと速い)です。私のマシンだとArchitectでおよそ20秒程度。

Unicodeについて

今まではString型がAnsiでしたが、2009ではUnicodeになっています。かなり詳しく書かれているページがあったのでリンクしておきます。
http://homepage1.nifty.com/ht_deko/tech014.html
コードページを指定した文字列型の定義ができるようになっています。
フォームのデザイナでも入力できていますね。

コードエディタではフォントの問題?のせいかハングルなどは表示できませんでした。
TMemoやら標準コンポーネントの挙動が気になっていたので試してみました。

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.SaveToFile('test.txt');
end;

フォームにボタンとメモを置いただけのアプリケーションで、TStringsのSaveToFileを使ってみます。この場合、保存されるファイルの文字コードはShiftJISでした。ハングル文字は"?"となっています。
今回、SaveToFileメソッドは、引数としてエンコーディングを指定できるようになっていて、例えばUTF-8で保存するには次のようにします。

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.SaveToFile('test.txt', TEncoding.UTF8);
end;

TEncodingクラスのクラスプロパティやクラスメソッドがエンコーディングを返してくれるようです。ちなみにBOM付きのUTF-8でした。BOMなしにする方法を知りたい。

Anonymous Methods(匿名メソッド)について

匿名メソッドを使えるようになりました。
Tiburon - Anonymous Methods
クロージャも使えます。

program sample_anonymous_methods;

{$APPTYPE CONSOLE}

type
  TIntFunc = reference to function: Integer;

  function Counter(init: Integer = 0; step: Integer = 1): TIntFunc;
  var
    count: Integer;
  begin
    count := init;
    Counter := function: Integer
    begin
      Inc(count, step);
      Result := count;
    end;
  end;

var
  c1, c2: TIntFunc;
begin
  c1 := Counter();     // c1 count = 0, step = 1 のfunction
  c2 := Counter(2, 5); // c2 count = 2, step = 5 のfunction

  Writeln('c1:', c1); // c1 Inc(count, 1) => 1
  Writeln('c1:', c1); // c1 Inc(count, 1) => 2

  Writeln('c2:', c2); // c2 Inc(count, 5) => 7
  Writeln('c1:', c1); // c1 Inc(count, 1) => 3
  Writeln('c2:', c2); // c2 Inc(count, 5) => 12
  Writeln('c1:', c1); // c1 Inc(count, 1) => 4

  Readln;
end.

出力結果。

c1:1
c1:2
c2:7
c1:3
c2:12
c1:4

reference toで宣言したtypeを使うときは、カッコの省略に気をつけたほうがいいかも。

Genericsについて

Win32Genericsを使えるようになりました。

program sample_generics;

{$APPTYPE CONSOLE}

uses
  Generics.Collections;

type
  THoge<T> = class
  private
    FValue: T;
  public
    constructor Create(Value: T);
    function GetValue: T;
  end;

  constructor THoge<T>.Create(Value: T);
  begin
    FValue := Value;
  end;

  function THoge<T>.GetValue: T;
  begin
    GetValue := FValue;
  end;

var
  o1: THoge<String>;
  o2: THoge<Integer>;

  o3: TList<Integer>;
  i: Integer;

  o4: TObjectList<THoge<String>>;
  j: Integer;

begin
  o1 := THoge<String>.Create('ほげ');
  try
    Writeln('o1:', o1.GetValue);
  finally
    o1.Free;
  end;

  o2 := THoge<Integer>.Create(12345);
  try
    Writeln('o2:', o2.GetValue);
  finally
    o2.Free;
  end;

  o3 := TList<Integer>.Create;
  try
    o3.Add(22);
    o3.Add(5);
    o3.Add(17);
    o3.Sort;
    for i := 0 to o3.Count - 1 do
    begin
      Writeln('o3:', o3.Items[i]);
    end;
  finally
    o3.Free;
  end;

  o4 := TObjectList<THoge<String>>.Create;
  try
    o4.Add(THoge<String>.Create('ほげ'));
    o4.Add(THoge<String>.Create('ふが'));
    o4.Add(THoge<String>.Create('foo'));
    //o4.Sort; THogeなのでソートできず
    for j := 0 to o4.Count - 1 do
    begin
      Writeln('o4:', o4.Items[j].GetValue);
    end;
  finally
    o4.Free;
  end;

  Readln;
end.

Generics.CollectionsユニットにTListなどのクラスがあります。
出力結果。

o1:ほげ
o2:12345
o3:5
o3:17
o3:22
o4:ほげ
o4:ふが
o4:foo

こんなこともできるらしい。
Owl's perspective: ジェネリクスでイベントのマルチキャストを実現

実行ファイルについて

ビルドして生成された実行ファイルは、相変わらず単体で動作(.netやらランタイムライブラリなどいらず)します。
ファイルサイズはボタンとメモを置いただけのアプリケーションで512KBでした。
Generics.Collectionsを使ったフォームアプリは変わらず512KB。
コンソールアプリでSystemのみだと25KBぐらい。
Generics.Collectionsを使ったコンソールアプリで123KBぐらい。

おわりに

Win32ネイティブなアプリで、ここまでできるって結構すごい。おそらく買う。