DelFusa Blog 総本山

プログラミングの話題とかです。

NEW | PAGE-SELECT | NEXT

≫ EDIT

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

| スポンサー広告 | --:-- | comments(-) | trackbacks(-) | TOP↑

≫ EDIT

Delphi Win32で、requireとensure その2 require実装


     \冂/
    Eミ゚Д゚ミヨi /7
 O) 「/~"ー"~~7/ ̄|
===二]匚ト<-  ノヲ弐ノ[]V/□∥╋|
     | j| |∥┃|
    几0(几)L二!
   ∠三ヲ/i二iヽ

『連邦の白いフサギコス-ツは化け物か。』

的な化け物コーディング中の漏れですが、

こんにちは。

ちょっと前回の内容はいきなりすぎたかもしれないですね。

玄人さん向けの記事を書いても一般受けしないのでもう少しわかりやすく Delphi Prism の require の仕様から押さえておきましょう。


Delphi Prismでは、このような記述が可能です。
  method TestA
  require
   条件A;
   条件B;
   条件C: 'メッセージ';
   条件D;
  begin
   …

  end;

Delphi Prism の method 指令は procedure と function が一つになった構文です。

ensure も同じようなものですが、requireはセミコロンで区切られた条件式を満たしていないものがあれば、そこで例外が発生するというもの、になるようです。(よく知らんがたぶんそんな感じ。)

だから、TestA メソッドの内部では、条件A~Dはすでに満たされていることが保障されているわけ。デバッグ時にとても便利です。

RemObjectの中の人の、センスが光りまくるというか、野望すら感じますね。.NET言語でありながら、C#を超えてしまおうとねらえるセンスはどこからわいてくるのでしょうか。

弱小ながらマイクロソフトを超えてしまうという心意気が、かつてのBorlandDelphiチームに通じるところがある気がします。

これを Delphi Win32 で実現するには、どうしたらいいかというと、通常無理ですが、無理無理頭をひねってみました。

セミコロン区切りで条件式を並べたりは出来ないので、まねっこをするにはオープン配列パラメータを使います。

条件式だけでいいなら、引数として array of Boolean なのですが、requireの場合には条件式とメッセージが並んでいます。(全く余計な構文を採用してくれますよ)
ですので、array of variant のオープン配列パラメータで渡しましょう。

require と ensure を共通化したり、デバッグ時もしくはデバッグビルド時だけの動作にしてみました。リリースビルドではrequireは何の動作もしません。

行コメントアウト対応のため、すべての行をカンマで終わらせてます。以前、ブログでネタにした、end_uses と同じ発想。最終引数で、要求する値をTrueかFalseか選べるようにしました。

つまり、
 require([
  条件A,
  条件B,
  条件C, 'メッセージ',
  条件B,
 true]);

このような記述を可能にしました。これがその実装。
引数が、Boolean なのか String なのかもチェックしています。

日本語に直すと、「Trueを要求する」って感じでしょうか、Falseを指定すれば、「Falseを要求する」になるのですが、あまりそういう条件では事前条件として書く機会はないかもしれません。

 require([
  条件A = False,
  not 条件B,
  条件C = False, 'メッセージ',
  条件B = False,
 false]);

とかです。

Variant指定しているので、コード補完は、BooleanでもIntでもStringでも何でも動作してコーディングがやりにくいということもありません。間違った型を指定すれば、実行時には例外が発生するので、わかるでしょう。

以下実装。これまたかなり短いです。
────────────────────
procedure CheckRequireEnsure(Values: array of Variant; ErrorMessage: String);
var
 I: Integer;
 CheckLastValue: Boolean;
begin
 if Length(Values) = 0 then Exit;

 //最終引数がBooleanであることを確認
 if VarType(Values[Length(Values)-1]) <> varBoolean then
  raise Exception.Create('CheckRequireEnsure Error. Args Last Value not Boolean');

 if Length(Values) = 1 then Exit;

 CheckLastValue := Values[Length(Values)-1];

 I := 0; while I <= Length(Values) - 2 do
 begin
  //Booleanであることを確認
  if VarType(Values[I]) <> varBoolean then
   raise Exception.Create('CheckRequireEnsure Error. Args Value not Boolean');

  if Values[I] <> CheckLastValue then
  begin
   if varType(Values[I+1]) = varString then
   begin
    Assert(False, ErrorMessage + ' ' + Values[I + 1]);
    Inc(I);
   end else
   begin
    Assert(False, ErrorMessage);
   end;
  end else
  begin
   if varType(Values[I+1]) = varString then
   begin
    Inc(I);
   end;
  end;
  //次の要素がStringなら一つとばす

  Inc(I);
 end;
end;

procedure RequireEnsure(Values: array of Variant; Message: String);
begin
 //IDE実行中かどうかを判定する
 if DebugHook <> 0 then
 begin
  CheckRequireEnsure(Values, Message + ' error ide debug');
  Exit;
 end;

 //DEBUGビルドかどうかを判定する
 {$IFDEF DEBUG}
  CheckRequireEnsure(Values, Message + ' error debug build');
 {$ENDIF}
end;

procedure require(Values: array of Variant);
begin
 RequireEnsure(Values, 'require');
end;

procedure ensure(Values: array of Variant);
begin
 RequireEnsure(Values, 'ensure');
end;
────────────────────
これで、Delphi Prism とそっくりの実装が実現してしまうというわけです。

というわけで、ensureの実装は次回ね。

ensureというより、Oldオブジェクトですな。

激難しいわけじゃないですが、アイデア次第で、びっくりするようなコーディングができるってところを、もう少し続けましょう。

スポンサーサイト

| 未分類 | 00:08 | comments:0 | trackbacks(-) | TOP↑

COMMENT















非公開コメント

PREV | PAGE-SELECT | NEXT

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。