メイン

Delphi アーカイブ

2008年09月25日

[Delphi] class helperが使えない件

いろいろ実験していたのですが、
Delphi8辺りから導入された class helperが結局のところ使えない件。
(今更ですけどw)

簡単に言うと、2つ以上の class helper が同時に適用できない。

コード:

実行結果:

Count = 3
All = Hoge in test, Moge in test, Mage in test,

Hit RETURN key!!

上記のコードの場合、
TListTestClassHelper だけが適用され、
TAspectClassHelper が適用されない。

class helperをそれぞれ各ユニットに分けた場合、
usesした順序でどれが適用されるかが決定されます。

う、うーむ。
いざと言うときに困る仕様だなー。
まあ、当初から言われていた不都合だけども。

もし複数class helper適用が可能ならば、
Ruby並みの mixin が可能な柔軟性を秘めるのですが……。

……でも、実は、
すでに似たようなことはできるんです!

必殺型キャスト!

実行結果:

start - TStringList.Add(Hoge)
end - TStringList.Add
start - TStringList.Add(Moge)
end - TStringList.Add
Count = 3
All = Hoge, Moge, Mage in test,
 
Hit RETURN key?

……できてない('A`)

型指定していてダックタイピングぽくなってないし、
こんなの mixin とか言ったら怒られる。
それに同じメソッド(add();)を拡張しようとしても、
2つ同時に適用はできてない。
(そもそも、型安全じゃない件)

全然ダメダメなオチだなあ。

次回は、そろそろ Delphi2009 について語ってみたいところだけど……。

[ Delphi ]

2008年09月20日

[C#, Delphi] C# 信者がうざい件

C# 信者の特徴

  • Hejlsberg は神であり神による実装である C# こそが唯一絶対の言語である
  • 他の言語(特に DelphiとJava)は存在自体が悪である
  • 他の言語を使っているのは C# を知らないからである
  • C# を布教することでそのような不幸な子羊たちを救済することこそが正義である

どこかの世界宗教のようですね。

「Delphiまとめwiki」 を読んでふと「C# 使えばいいのに」と思った - World Wide Walker

DMWより先に、Delphiを選択する時点で、C# よりも Delphi を使いたいという前提があることを考えて欲しい。

その上で Delphi をよりよく(という言い方もあまり好きじゃないけど、ほかにいい言い方が思い浮かばない)運用する方法がDMWなんだろ。

それに対して「それ C#(略」っていう発言は場違いであると思わない?

Delphi の The best way is only one. と言う考え方は好きだけど、実際には one of them だったり、後から小声で But, there are many ways to do it. だなんて言われそうな気がするのがなぁ、と思ってしまう。

当然 only one だろ。

その only one だから more better なものを選ぶ必要がない言語を選択するのがエンジニアとしては当然なんじゃねーの?

あと many ways なんて言語は存在価値はないよ。

IsValid や HasFound など真偽値にちなんだ名前にする。

foo.IsValid や bar.HasFound と書ければ一目瞭然。

そうでもない。関数名にCamelCaseが来るという時点でまず C# 使わない人間から見ると異常。

あとこの例だと bar.HasFound は HasFound という意味より IsFound という意味に俺は取ってしまったんだが。

省略するのはいいけど、省略しすぎて情報が落ちてないか?

必要なときはforwardによるプロトタイプ宣言を使う。

なぜプロトタイプ宣言やinterface節での宣言がいるんですかね(もちろん過去互換性のためだろうけど)。

プロトタイプ宣言なしだと関数やメソッド名などをtypoしたときに 爆速コンパイルの 1 pass 時点でエラーにならないからだろJK。

ループで配列やハッシュのインデックスを使わない。配列を直接ループさせる。

そもそも、Delphiはまともな Hash ライブラリすらないからな。TStringListのValuesプロパティは遅いから THashedStringList を使うなんてのは Bad Know-how 以外の何者でもないな。C# なら System.Collections.Generic.Dictionary で明瞭にかける。

インデックス回して書いた方が人間が見てわかりやすいならそう書くべき。

その上で必要ならチューニングする。

DMWもこれ書いてる人が考えるBestなだけで、実際にこれがBestだと決まってるわけじゃない。

[Ruby] C# >>>(越えられない壁)>>> Delphi (第一種臨界不測日記)

このような開けた場所で不等号を並べて越えられない壁とか臆面もなく書けるあたり尊敬します。

しかし、Webの記事とか、googleで上の方に出てくるのとか、

その辺、全然考慮してなかったりするんだよヽ(`Д´)ノ ウワァァン!!

Delphi のコードは Google などで検索するとレガシーなコードの方が多くHITしてしまいます。

これは Delphi は C# に比べると歴史が長いため、レガシーなコードほど多く蓄積されてしまっているからじゃないかと考えています。

良質なコードを摂取したいというのならば最近更新されていて、よく使われている評価の高いCode Central のコンポーネントのソースを読むことをオススメします。

使っている人もgeekな人が多いせいか、

C#を使っている人=geek=自分は geek ということですね。

自分で自分のことをgeekと言う人ほど信用できないものはないと思います。

最後に
自分の考えをまとめると、Delphiが全てのエンジニアにとって使いやすい言語ではないのと同じように、C#も全てのエンジニアにとって使いやすい言語ではないということです。

別にC#という言語やそのコミュニティが嫌いだというわけではなく、このことを忘れて(あるいは考えず)、他の言語をDISってC#をプッシュしてくる信者が大変鬱陶しいということ。

GUIといえばDelphi/VCLだった時を考えてください。

この時代にあなたが生まれていたとしたら、Win32の世界に入りましたか?

答えはYESですよね?それは嬉しいことじゃないですか?

色々な言語がクラアントサイドの言語として使われることで、幅広い層のエンジニアがリッチクラアントの世界に足を踏み入れるわけです。

それによってそれぞれの言語のコミュニティが活発化して、お互いに影響しあって成長していくんじゃないですか?

言語がどうこうなんて小さいことじゃなくて、もっと大きな視点を持つべきなんじゃないですか?

元ネタ:いい加減Ruby信者がうざい件 - id:k-z-h

[ C# , Delphi ]

2008年02月08日

[Delphi] 【緊急告知】Delphi使い必見!公式のDelphiアンケートに答えよう!

Delphi2008年度アンケート

いろいろ書きたいことがあるのですが、今日はとりあえずこれ!

CodeGear 公式の Delphi アンケート が募集されてます。

2008年度 Delphiアンケート

日本のユーザーの意見を伝えるチャンスの一つです。
長いですが、Delphi ユーザーはぜひ!

(アンケートの内容に関する"たわごと"は長くなったので、読みたい人だけ続きでどうぞ ↓ ↓ ↓ ↓ ↓)

続きを読む "[Delphi] 【緊急告知】Delphi使い必見!公式のDelphiアンケートに答えよう!" »

[ Delphi ]

2008年02月03日

[Delphi] Assigned(Obj) か if Obj <> nil か?

Delphiのポインタが nil かどうかチェックするのに、
Assigned(Obj) か if Obj <> nil then を使うか?

この長年の疑問についに終止符が!!
……って、しらなかっただけです。

↓詳細はこちら
DelWiki - 資料/Assigned

……よくわかりません、が、超意訳してみると

Delphi のメソッドポインタは、
オブジェクトのインスタンスと、
メソッドノアドレスの2つを含む構造体そのもの。
まあ、これはいいですよね?

で、Assignedのときは、nilチェックは
その構造体の片方しかチェックしない。

そして、メソッドポインタの片方に内部的な値が入るときがある(へえー)。

ということで、その場合用に Assigned(Obj) を使っておけば安心。

結論:
メソッドポインタには Assigned(Obj) を使っておきましょう。
その他には、if Obj <> nil then でも大丈夫。

というか 全部 Assigned(Obj) でいい。

あとで検証して見る予定。

[ Delphi ]

2008年01月11日

[Delphi] Delphiでも高階関数使いたい!ヽ(`Д´)ノ ウワァァン!!

2chでみた C#のコード

とか見て、Delphiでも無名関数実装してください!
と切実に思う日々。

Rubyになると、ブロックで高階関数をさらに手軽に使えます。
高階関数ほすぃ~~。

一応、Delphiでも、関数内関数で無理やりやる高階関数する方法は、YTさんが開発して下さったのですが、やっぱり、正式サポートがほしいし(ポインタ渡しで安全じゃないので)、
無名関数がないとウマ味が半減。
ブロックまでほしいとはいいませんけど。
※Delphiの関数内関数で高階関数する使い方は、一度まとめておきたいところ

ちなみに、ObjectPascalを採用した、.NET用の言語 Chrome は、無名関数やら、Lambdaやらが実装されていて、
まるで次世代版 Delphi になってます。

その進化具合は、

Delphi.NET = う ん こ ?

と言い切ってもいいくらい。

例:

無名関数のコード

Lambda記法のコード(式内でお手軽無名関数。関数型言語っぽく)
LINQ用らしいが使えそう。

RemObjects Software: Chrome 'Joyride': Language Features より

Chrome ほしすぎるだろ……これ。

[ Delphi ]

2007年12月21日

[Delphi] 内部エラー: URW821 出まくりんぐ

Delphi 7以降の言語およびコンパイラの新機能
にある、「メソッドを持つレコード」を使っていたりするのですが、

的なコードで、

Hoge := (FPoints[i] - Position).Length;

とすると、コンパイルする時に、

[Pascal 致命的エラー] PathUnit.pas(98): F2084 内部エラー: URW821

とでて、プロジェクトが、コンパイル不能!

AA_Booo.png

Quality Centralに報告発見……。

2007年3月に、Fixedされている模様。
Delphi2007では大丈夫なのかな?
Report #: 30131 : "Advanced" Records - Internal Errors URW821 and C1624

前にもバグらせて、Quality Central にバグ報告しましたが、
やっぱり、Delphi7以降の新機能の record 周りは鬼門だ。

完璧なもの出して、とは言いませんが、
パッチで直してホスィが、BDS2006はすでに無理!

ちなみに、今回の回避コードは、以下。

Hoge := (FPoints[i] - Position).Length;

ではなく、

で、OK。
recordの関数作った意味がないwwww

しかし、一見、機能拡張ではなく、
「コンパイルのバグのせいでDelphi2007より前では、
コンパイルが通らないコード」、っつーのが量産できそう orz

クソ!俺も、ベータテストに参加できれば!
と思って、参加要請出したのが、4ヶ月前……。
時間なくて(あるけど)、返事出してない(´・ω・`)

[ Delphi ]

2007年10月12日

[Delphi] Squirrel 組み込み中断 /(^o^)\

squirrel

時間の都合により、Delphi の Squirrel 対応は、中断となります。
というか、時間かけすぎて時間切れ!

期待された方、ごめんなさい。

というか、Squirrel が予想以上に複雑で、自分の頭では、把握に時間かかりすぎた orz
あと、公式wikiのリンクにもある便利に使うためのアドオン(SqPlusとか)が、C++テンプレートベッタリで、理解と移植がマジムズイ件

現在のプロジェクトでは、たぶん当分は、スクリプトの代わりに、データ定義は、xmlで行くことになりまする。

一応、C言語レベルのヘッダーは、一通り .pas にコンバートできてて、
途中成果だけでも出しておきたいのですが、
公開の方法は、どうしようかなー。

sourceforge当たりに、プロジェクト申請してもいいけれど、
いつ再開できるかわかんないんすよねえ……。

[ Delphi ]

2007年09月12日

[Delphi] 最近の CodeGear(Delphi) の動向

とりあえず、最近の CodeGear(Delphi) 周りの動向をまとめてみる

  • Delphi2007 の update3が出て、バグが大量に(500個)直る模様
  • Delphi、Delphi.NET、C++Builder を統合した CodeGear RAD Studio 2007 が発表された
    が、値段がやたら高い。
    BDS2006 の上位バージョンっぽいです。
  • Highlander(次期開発環境)では、C# と WinForm は、サポートされない
    C# Builderも開発終了っぽい
    開発リソースないのだから、妥当だと思う。
    つか、C# なら、VisualStudio.NETに任せておけばいいと思いまする。
  • 待望のジェネリックスが Delphi.NET でついに対応された模様。
    Win32版キボン!!
    ちなみに、このプリプロセッサの拡張 を使って無理やりWin32でジェネリクスできますが、かなり人柱風味。
  • 定番の UNICODE コンポーネント TNT が買収され、有料化 orz
    無償版は、SpTBXのページより、まだ入手可能
  • ひそかに、Delphi 2007は、コマンドラインのコンパイラが条件付で配布可能
  • 今後、散々言われ続けてきた、ヘルプ(ドキュメント)の充実が期待できそう

という感じです。

Delphi 2007ほしいけど、Highlanderがあるからなー。

ちなみに、今、CodeGear から出ている開発環境は、

  • Delphi 2007
  • C++ Builder 2007
  • RAD Studio 2007
  • J Builder 2007
  • Delphi for PHP

これに、Delphi.NETがあるとすると
6本もあるんかい!

さらに、Ruby(Rails)の開発環境も出す予定のハズ。

開発リソースあるんかいな……
(C#は切って正解ですわ!!)

[ Delphi ]

2007年08月03日

[Delphi] Squirrelわかってきた(・ω・)(変数の値の取得、自作ライブラリ編)

squirrel

とりあえず、生のAPIで、変数取得するルーチンとか、書きつつ、
SqPlus(DXSquirrel)のソースを眺めていたら、
少しは、構造がつかめてきた。

やっぱり、ソース読んだり、実際に書いたりしないと駄目だねー。

自作ライブラリも、DXSquirrelのライブラリ的な基本構造を参考に、作ってみてる。

というか、ほとんど、SquirrelVMとか、SquirrelObjectとかを、使いやすいように移植という感じw
ただのコピペではなく、自分なりに、消化しつつ書き書き。
さらにある程度、理解しているので、バグってても直せるからよいのですよ。
(SqPlusのバグ見つけたりもした。本家の掲示板では指摘されてた)

理解は重要だなぁ。

ちなみに、前に書いた「変数の中身を得る」というのは、

TestString <- "hoge"
TestInt <- 1234
TestBool <- true

という、Squirrelソースがあった場合、
自作ライブラリを使うと、こう書ける。

TSquirrelObject.Get は、Variant で返るので、自動で型に合わせてくれる。
Hashライクな、TSquirrelObject["文字列"] でのアクセスも、TSquirrelObject.Get と同じ。
(Squirrelのスロット表現は、Squirrelでもハッシュ風に書けるので採用)

まだ、ちょっと面倒だけど、もう少し簡単にできるようにしたい。
(例えば、面倒なので、TSquirrelObject.Get じゃなくて、直接 SquirrelVM.Get でも行けるようにするとか。後は、interface実装にして、TSquirrelObject.Releaseいらなくするとか)

SquirrelVM.GetRootTable ってのは、RootTable を得ている。
RootTableは、Rubyで言えば、main みたいなもので、
ソースのトップレベルでの暗黙の This みたいなもの。
(Squirrelのソースで、Hogeと書いても、実際には、RootTable.Hogeなのだ)

TSquirrelObject は、RootTableを含む、Squirrel内のオブジェクト表現をラップしたものです。

これで、スタックはあまり意識しなくていいはずだけどなあ?

さて、その他に実験して、Hoge.Foo.TestInt などを一発で取得する方法も分かった。
これは後ほどね。
(ちなみに、上記方法では一発では、得られないのです)

[ Delphi ]

2007年07月19日

[Delphi] Squirrel挫折進行中(変数の値を得る編)

squirrel

なかなかに情報が少ないため、Squirrel、挫折しながら進行中。

変数ひとつ得るにも一苦労……。

TestString <- "hoge"
TestInt <- 1234

というのがスクリプト上にあった時に、上の変数の中身を得たい。
(Squirrelは、初回代入は <- でないとダメな仕様なことに注意。スロットの作成というらしい)

文字列変数の中身(TestString)を得たいときは、呼び出し側(Delphi)で

  1. sq_pushroottable
  2. sq_pushstring
  3. sq_get(変数オブジェクトゲット)
  4. sq_getstring(変数から文字列へ)
  5. sq_pop(後始末)

具体的に、生のAPIを使うと、こういう感じ。
(FSquirrelVM は、あらかじめ、sq_openして得ておくとする)
(下記コードは、UnitTestのコードなので、ご了承を)

整数の変数の中身(TestInt)を得たいときは、同様に

sq_pushroottable -> sq_pushstring -> sq_get -> sq_getinteger -> sq_pop

という感じです。

長っ!
これは、めんどうくせー('A`)
エラー処理入れたら、10行近くになる。
Luaもこんな感じだったけ?(忘れた)

上記の方法だと、TestIntとか、TestStringしか取れないので、
TestInt.Hoge.Foo とか得るときにどうすんだろう、と。

一発で、変数名を渡して、評価する方法ないのかなー。

[ Delphi ]

2007年06月23日

[Delphi] Squirrel for Delphi 苦戦中

squirrel02.png

[Delphi] Squirrel DLLできた (第一種臨界不測日記)の続き。

我ながら、苦戦中。
今回、長文にて失礼。

  • Squirrel のコンパイルテスト
  • Squirrel の dll 化
  • Squirrel の Delphi 版ヘッダー作成
  • コンパイラ兼実行環境 sq.exe の Delphi 版、sq_del.exe の作成
    (↑ここまでオワタ\(^o^)/)
  • SqPlus みたいな、すんげー使いやすいクラスライブラリの作成
  • Delphi + Squirrel をバリバリゲームに使う!(うっとり)

ここまで、二週間。
時間かけすぎだわ!

ヘッダー作成時の苦労話。

前に書いたように
可変個引数(varargs)の問題を解決できなくて、
一か所しか呼ばれてないと思って、固定引数にしたものの、
実は、print文や、エラー出力等において、
ポインタ経由で呼ばれまくってたことが発覚(^ω^#)ビキビキ

けど、ようは、printf を外部に丸投げしてるだけじゃねーかYO!!
printf=可変個引数。
確かになっ。可変個引数なんて所詮は、printfのためのもの。

つーわけで、squirrelのソース書き換えの方向性で。

squirrel の DLL内で、_snwprintf を使い
文字列をあらかじめフォーマッティングして、Delphiに固定引数で渡すようにして解決!しますた
つまりは、printfを可変個引数で、外部に丸投げしないで、DLL内で自前で文字列処理させて、出力のみDelphiに渡す方向。(わかりにくい)
(_snwprintf が、VC++で、警告出るけど、キニシナイ!!というか他にいい方法あったらおせーて)

……さて、
Squirrel の .nutファイルをコンパイルして実行する sq.exe の Delphi版の sq_del.exe について。
とりえあえず、.nutファイルをコンパイルと実行はできるようになりました

面倒なので、対話モードはまだつけてません ('A`)
(対話モード = Interactive Mode。コマンドプロンプトが出て、逐一実行できる。機能的には、本家のsq.exeにあるから、いらんのだけど、ま)

しかし、UNICODE対応にすると、回りがすんげー面倒くさいなー。
いちいち、WideString にキャストして、PWideString でほうらなアカン。

ちなみに、上記に書いた、可変個引数の問題の解決のおかげで、
コンパイルエラー出力等がまともに出るようになってます。

さーーーーてーーーーー。
一番の問題は、SqPlus のようなクラスライブラリ。
SqPlus が C++ の binding で、よさげなのですが、
C++ の template と#defineマクロバリバリで、そのまま移植は無理くさいですわわわわわわ。

付属のサンプル見ると(testSqPlus2.cpp)、
かなり使いやすそうなんで、参考にはしたい!
参考にするだけ!

そもそも、SqPlus 並のライブラリがないと、
スタック操作とかワケワカメで、
まともに使えそうにないのが問題なのだが (´д`;)
(プログラマだから、スタックなんてわかると思いきや、アレは人間がいじるもんじゃねえと再確認)

どうでもいいけど、SqPlus に、
Squirrel から DirectX を呼び出す、
DXSquirrelが付いているのにはビビッタ。
(SqPlus自体、DXSquirrel の改編版?みたいだけど)

Processing とか、sgl @ RubyNodeBox @ Python みたいに、
お手軽 インタラクティブアート環境に、化けるかも?
と、思ったけど、そこまでではないのかな?

いや、DirectX の SDK入れてないからコンパイルできなかたわけだけど……。

参考リンク

[ Delphi ]

2007年06月21日

[C#, Delphi] Sort と C# と Delphi と

sort

仕事のことで、C#でツールを作ってもらっているんですけど、
C#の言語仕様になかなかなれない様子で、
リストの sort の評価関数に delegate つっこむのがキモイとか、評判でした。

これのこと?

なんでも、イベントハンドラに delegate はまだ許せるが、
ジェネリックなコレクションクラスを利用するときに、
sort の評価関数に delegate 使うのはどうなんよ?
継承でいいじゃん?って言うことらしい。

自分的には、カスタムな sort するくらいのことに、
継承なんて問題外なんですが、これって、
そもそも Delphi といっしょだよなあ、
慣れだよ、慣れとか……。

そのプルグラマは、C++ 出身なので、特にキモく感じるらしい。
C++ 流だと、継承なのか?と思ったけど、単に、メソッドポインタがないので慣れないせいかも。

それはそれとして、
sort すんのに、呼び出し側で、メソッド定義するのは
面倒という話も聞いたけど、
(C#なら、Delphiと違って、宣言いらない分楽だと思うけど)
それならば、C# 2.0 の匿名メソッドでいけるじゃんよ?
って話しに。

つまり、こう

さらに、Rubyとかやってると、匿名メソッド(というか、ブロック構文ね)とか、普通ですよ?とかいう話にも。

以下は、Ruby で、配列をランダム に sort するワンライナー(一行コード)。

楽ちん?

第一、Javaなんてば、java.util.Comparator 継承して、
delgateの代わりに、new HogeComparator 渡すんだぜ?
なんて話まではいかなかったけど。

何が言いたいかって言うと、
別に、C#に慣れないって話しではなく……。

C#って、
イベントハンドラ周りが delegate だったり、
delegateってようは、メソッドポインタ相当とすると、
Delphiと大してかわらんねー?、
これならいつでも移れるね?という安心感があるなという話。

さすが、Hejlsberg(C#設計者) だぜ?

とはいえ、C# 2.0 の匿名メソッドや、ジェネリック、イテーレタの yield が
うらやましすぎるけど……。

クソー、C#が、ネィティブ対応してれば、今頃は、連邦のモビルスーツな(ry

そういや、
去年くらいから、Ruby流行ってるって言っても、
ピンと来てないらしく、
そのプログラマさんは、
Ruby on Rails もご存じではなかった。

たぶん、Rubyの知名度ってまだまだその程度のなんだろうと思う……。

[ C# , Delphi ]

2007年06月14日

[Delphi] 可変個引数の扱いがわかんね('A`)

squirrel のヘッダーをコンバート中。

C言語の可変個引数の扱いがわかんね。
どうコンバートすればいいんだろ。

exturnな、API呼び出しなら、

例えば、Win32APIの wsprintf なら

function wsprintf(var Output ; Format: PChar): Integer;
  cdecl; varargs; external 'user32' name 'wsprintfA';

みたいにしてやれば、varargs 使えば、

wsprintf(pchar(s)^,'%5d %5d', 1,100);

みたいに呼び出せますが、
(フルソースコードは、こちらに書いておきました
今回は、呼び出しではなく、呼び出される方でして、
困っています。

つまり、C言語側から、可変個引数の関数として呼ばれるDelphi関数の定義の話。

自分の出した結論から書くと、可変個部分は無理。
というか、こちらの方法で、可変個部分にアクセスはできるけど、
引数の数が取得できない。

可変個じゃなくて、固定部分なら可能という結論。

上のtoryyのページを参考に、Delphi内で呼び出す場合を書くとこんな感じ。

出力結果

Hello World HogeMoge

cdecl だから、引数の数が、スタックにでも積まれていると思っていたが、
CPUウインドウで見ても、見つけられなかった。

というか、cdeclがよくわかってなかったりする。
呼び出し側責任で、右側から順にスタックにつまれる、くらいしかー。

可変個できなくてよいかな……。

[ Delphi ]

2007年06月13日

[Delphi] Squirrel DLLできた

squirrel

組み込みスクリプト言語は、Squirrel に決めました。

苦労したけどようやく DLL ができた。

UNICODE対応でのコンパイルがうまくいったので、
国際化もできるぜ!!(スクリプト側だけだけど)
(VC++2005で、別プロジェクトをリンクしているのに、別プロジェクト側で#defineし忘れてて、#defineしてない .objと、してる.obj を混ぜてしまい、バグらせてしまってて、それに気づくまで、すんごい手間取ってしまった orz)

あとは、ヘッダーをコンバートしないとなー。
これが大変。
本当は、SqPlusとか使いたいけど、テンプレートバリバリで無理。

コンパイルの仕方等は、wikiにまとめておきます :D

参考リンク

[ Delphi ]

2007年04月15日

[Delphi] Dependency Injection?

Javaなんかで、DI(Dependency Injection)っつー、
概念がありまして、
妙にもてはやらされていたころが、あったんですが、
(今も?)
これがなんなのか、よくわかってませんでした。

この前、
『Dependency Injection の基本的なアイディア - いやなブログ』
を見て、氷解。
そうか、依存性注入ってそういうことか!

Javaとかだと、フレームワークとか使うみたいですが、
そんなんなしにして、
手っ取り早くDelphiでもできんのかなーと思っておりました。

interfaceを使うのもなーってとき。
小規模な時。
手っ取り早い方法を書いてみたい。
(interface版は、また後で)

Delphiなら、メソッドポインタ(TNotifyEventやら)を作って、
依存性を外部におけばよい。
それだけじゃん。

例えば、THogeってオブジェクトがあって、
ログをとりたいが、ログ取り用の Logger オブジェクトは一応あるんだが、
それに依存させたくないなーって、場合。

※HogeOnLog;が、間違っていたので修正orz

おー、簡単にできるじゃないか。
っていうか、Delphi使いなら、誰でも知っている、
あたり前田のクラッカーなテクニック。

これで、使う側でメソッドポインタを定義して、いろいろ指定してやれば、
他のユニットに依存しなくてすむ。

まー、もっとも、上のページの Ruby の例のような、
柔軟にはいきませんけど。
(あれは、型なし言語だからできる技だよな)

[ Delphi ]

2007年02月16日

[Delphi] ポール・グレアム「プログラミング言語が解決するもの」が面白い

らいおんの隠れ家 - ポール・グレアム「プログラミング言語が解決するもの」

という翻訳物が、面白いです。
ある言語は、ある言語の不満を解決して作られているということですな!

Pascalが解決: Algolにはデータ型の種類が足りない。
(略)
Rubyが解決: Perlはその場しのぎだし、Lispの文法はおっかない。

なるほど。
しかし、Delphiがないな。
というわけで、Delphiを勝手に追加。

Delphiが解決:C++には GUIライブラリがないし、VisualBasic(Java, C#)はネイティブ・コンパイルできない。

C++ Builderが解決:Delphi には、end が多すぎる。

いいのか?('A`)

しかし、知らん言語がある……T言語って何だ?

ところで、らいおんの隠れ家さんとこは、翻訳物がやたら面白いです。

[ Delphi ]

2006年12月10日

[Delphi] .NETを使うか否か?

で、Delphiと関連して、.NETなんですが、
自分としては、C#の設計者のヘジルスバーグについて行きたいのですが!

一番の問題は、

『.NET ランタイムの普及度』

……これですね。
.NETランタイムがないと、.NETのソフトは動かないわけですよ……。

Delphiがよく使われる理由でもある、

『出力された実行ファイルがネィティブかどうか?』

という点とも関連性があります。
一般に、Delphiで作られたソフトは、外部のランタイムが要らないと言われています。
(厳密には違うけど、実質はそういってもいい)

というかですね、自分の身近な環境ですら、いざという時に、
「.NETのソフトが、ウゴカネー!ウゴガギギ!!」とかいうことがあるとですね、
.NETランタイムの一般の普及度は一体ぜんたいどの程度なのか?と!!

そう思うと、どうも使う気が……。

Windows Vistaで、.NETランタイムが標準搭載ということで、
期待していますが、
これが一般に普及するのは相当、後だし……。

Microsoftさん!Windows Updateで、標準で、.NETランタイム入れてあげてください!(強制的に!)
と願うばかり。(こんなところで言ってもなあ……)

当分は、ネィティブに縛られるのか……。

「Delphi使いというのは、その時、その時にベストな開発環境を使う人達のことなんだよ!
(たまたまそれが、Delphiだったんだよ!)」
「Delphi死滅しちゃっても、次に乗り換えるだけさ!」
なんて、2chで言われていたこともありますが、

果たして、次があるのか?なんて……。
.NETがそうなることを期待して。

[ Delphi ]

2006年12月09日

[Delphi] 何故、Delphiか?

話題休刊。たまには、Delphi話でも……。

自分が何故、Delphiを使い続けるのか?

ちょろっと、VisualStudioとか、Eclipseなどを使ってみて、わかりました。
簡単なことでした……

Borlandの環境と言語に慣れているから

Ctrl+Tabの挙動が違うだけで、キレそうになりますもん(笑)
他の言語で、関数内関数が、書けないだけで(ry

理由が、面白くネェーーーー。
慣れているっていうことは、重要だけど、
技術者として、どーなんよ?という気モス

DelphiのライブラリであるVCLも、さすがに、もうロートルだからなあ。
コンテナも少ない、標準だと、UIも古くさいしね。
(サードパーティ製があるのが唯一の救い)

移れるなら、さっさと、.NETに移りたいなあ。

[ Delphi ]

2006年10月09日

[Delphi] Handle改良案

大分前に書いた、オブジェクトに対するハンドルを
なんとか簡単に使えないかというお話。

procedure ChildAttack;
var Child: TChild;

begin
Child := TChild(FChildHandle.ToObject); if Assigned(Child) then // ← Child <> nil と同じ Child.Attack; end;
ChildAttack;

これを簡単にする方法を思いついた!
高階関数を使えばいいんジャマイカ?

type
 TDoMethod = procedure(const obj: TObject; context: Pointer) cdecl;
  
 TO3HandleHelper = class helper for TO3Handle
   procedure DoMethod(method: TDoMethod; context: Pointer);
 end;

{ TO3HandleHelper }

procedure TO3HandleHelper.DoMethod(method: TDoMethod; context: Pointer);
var obj: TObject;
begin
obj := ToObject; if Assigned(obj) and Assigned(method) then method(obj, context); end;

みたいな helper class を定義しておいて、

procedure ChrAttack;
 procedure DoAttack(const chr: TCharacter); cdecl;
 begin
   chr.Attack;
 end;
begin

Handle.DoMethod(@DoAttack, GetContext); end;

で、いけるネ?
行数増えた? (゚ε゚)キニシナイ
時代は、DRY(Don't Repeat Yourself)原則ですよ!

仮想コードはいいよ!実行できるソースコードくれ!
という意見が多い(脳内で)ので、
ここに置いておきますね

GetContextに関しては、λ with INNER FUNCTION を参照のこと。
しかし、このテク、.NETだと無理くさい?

[ Delphi ]

2006年09月11日

[Delphi] Turbo Explorerキタ!

turbo_explorer_2006_09_11.png

キタ!キタ!キタ!ついにキタ!
先日、Borland の Turbo Explorerがダウンロード可能になりました。

Turbo Explorerは、Borland社のDelphiやC++、C#を統合した開発環境、
Borland Development Studio(以下BDS) 2006 の単体販売版(つまり、切り売り)です。

Turboという名は、昔のBorland社のブランド名ですから、
懐かしい人は少なくないはず。
自分も、DOSのころ Turbo C++ をもっていました。
名前としては、自分は、よい印象を持っています。

今回のTurbo Explorerの特徴は、言語別の切り売りということもありますが、
むしろ、商用開発も可能な無料版も配布されている点でしょう。

これは、Borland の統合環境としては、
Delphi6 Personalが無料配布された以来です。
# こちらは、商用開発不可でしたけど

無料版は、

  • 外部コンポーネントがインストールできない
  • IDEの拡張ができない

という欠点がありま……って、それは致命的な気がしてきます。

外部コンポーネントがインストールできないということはですよ。
定番の JVCLとか、TBXとか、TNTなどが利用できないってことです。
これは非常に困る。
というか、外部コンポーネントなしでは、Delphiの性能は半分も発揮できないように思う。

まあ、インストールをしなくても、ソースにパスを通して、
非ビジュアルコンポーネントを扱うように、
ゴリゴリコードを書けば、コンポーネントを使うことは可能でしょうけど……。

一応、無理やり外部コンポーネントをインストールする方法はあるようですが、
やはり、ライセンス的にマズイよなあ・・・。

あと、IDEの拡張できない件は、そうでもない様子で、
例えば、定番のGExpertsはインストールできるそうです。

って、自分の場合、コンポーネントをインストールしなくてもコンパイル通るように、
ゴリゴリコードで書いてるし、GExpertsが使えるなら、
Turbo Exeplorer でいいのかもしれない。

どっちにしろ、試してみないと、と思い、
無料のTurbo DelphiとDelphi.NETを落としてきたのですが、
製品版の BDS2006 がすでに入っているから、
インストールできないとか言われてしまって、ガックシ!!

な、なんじゃそりゃー。

えーー、既存環境(というか2006と)と共存できないのーーーー?
BDS使っている人には使わせない(評価させない)戦略とか思ってしまうぞー。
本当は、まあ、バージョン番号が、2006になってたりするという話から、
時間がなかったということなんでしょうね。

無理やりインストールする方法ないのかな。

[ Delphi ]

2006年05月25日

[Delphi] Delphi2006←殴っていいですか?

最近のバージョンに搭載された演算子オーバーロードを使おうと思ったのですが、
どうも使えない様子。

そもそも、ヘルプに演算子オーバーロードに対する記述がない。
おい!
ヘルプに記述ありました。
キーワードだと「演算子のオーバーロード, クラスとオブジェクト」で、
URLだと、ms-help://borland.bds4/bds4ref/html/OperatorOverloads.htm
です。YTさんサンクスです。
↑俺アホだー。よく見てないのがバレバレです。

とは言え、\Program Files\Borland\BDS\4.0\Demos\DelphiWin32\VCLWin32\ComplexNumbersにある、
サンプルを見れば大体わかるので、
まあそれはよしとする。

で、使おうと思ったんですよ。
ところが、どっこい!どうやら、object型には使えない!

なんで、object型にしてあるかと言うと、
例のコンパイラのバグを回避するために
record型をobject型にしてあるんです。

つーか、なんで、object型で新機能の class var は使えて、
class operator は使えないんですかい!
中途半端にクラスより?

……つまり、まとめるとですね、
新機能使うには、recordを使え、と。
でも、recordはバギーだから使えませんよ、と。
つまり、演算子オーバーロードは使えない orz
↑殴っていいですか?

駄目だぁああ。
最近のDelphiイヤポ……。
素直に新機能使うなってことですかいな。
この調子だと、次の次あたりで、要望の高い generics が入っても、
次の次の次あたりになるまで、使えなかったりするんだろうか。何年後だよ!
もう、Borlandにお布施すんのやめようかな……。

つか、日本でこの辺の報告を聞かない辺り、
誰もDelphiの新機能を使ってないんじゃあ?とか思えてくるんですが orz

……マジ泣けてくる。

[ Delphi ]

2006年04月29日

[Delphi] コンパイラのバグ!?

久々のDelphiのバグキタ━━━━━━(゚∀゚)━━━━━━ !!
ゲーム絶賛開発中に、勘弁してくださいよ、もう。

Delphi2006で出ました。他のでは確認してません。
内部エラーURW813ってのです。
昔もたまに出たけど、内部エラーって回避しにくいだけに困ります。

とりあえず、再現コードを晒しときます。

TestUnit.pas

unit TestUnit;
interface
type
  TTestRecord = record
    Value: Integer;
    procedure Moge;
  end;

  TTest = class
    function Hoge: TTestRecord;
  end;

implementation

procedure TTestRecord.Moge;
begin
end;

function TTest.Hoge: TTestRecord;
begin
end;
end.

ErrorCodeUnit.pas

unit ErrorCodeUnit;

interface

uses TestUnit;
procedure ErrorCode;

implementation

procedure ErrorCode;
var
  Child: TTest;
begin
  Child := TTest.Create;

  // ↓ここがエラーになる
  Child.Hoge.Moge;

  Child.Free;
end;
end.

Project1.dpr

program Project1;

{$APPTYPE CONSOLE}
uses
  TestUnit in 'TestUnit.pas',
  ErrorCodeUnit in 'ErrorCodeUnit.pas';

begin
end.

てな感じで、構造体にメソッドを宣言して(最近の新機能ですな)、
他のユニットから間接的に使うだけで死亡。
新機能、つかえねーーwwwww(けっこう笑い事じゃない

前回の(2005の時の)教訓をいかし、他人任せにしないで、
とっとと、Quality Central にバグ報告しときました。
Quality Centralを見ると、すでに報告されているReport#:22869が近いのですが、
念のため報告しておきました。

ちなみに、回避方法。

TTestRecord = record
  Value: Integer;
  procedure Moge;
end;
を、
TTestRecord = record
  Value: Integer;
end;
procedure Moge(Test: TTestRecord);
などどして宣言する。
つまり、新機能は使わな(ry

ふう。
有償デバッグはもうなれっこだけど、
それだけで、1,2時間、足止めくらうから勘弁してください。

[ Delphi ]

2006年04月23日

[Delphi] ハンドル再考(Dangling Pointer編)

すでに解放されている場所を指すポインタ問題について。
これを、ハンドルで回避していたんだけれど、
この問題ってぶらさがりポインタ(もしくは、懸垂参照、英語ではDangling Pointer)っていう有名な問題なんですね。
知りませんでした。

ぐぐったら、一杯出てきました。

とりあえず、このDangling Pointer を回避するには、

  • 直接ポインタは使わず、参照カウンタつきポインタみたいなのを使う。
  • 開放処理を一切なくして、GC(ガーベジ・コレクション)を導入する

両者とも、解放されることを考えないので、
ハンドルとは、根本的に解法が違います。

前者の方は、C++とかでライブラリあるんじゃないかと思い
探してみましたら、std::auto_ptr とか boost::shared_ptr とか
のスマートポインタのことでした。
これなら、参照されている限り、解放されないので、nullチェックもしなくて済むかー。
むかしDelphi-MLでauto_ptrする方法が、あったような。

後者の方は、Delphiにない物ねだり。
またですかーーーヽ(`Д´)ノ
あ、でも、前にどこかでDelphiで、GC使う方法みたぞー。
(YTさんとこかな?)

まあでも実は、これ使ってもそのままでは駄目なんですね。
ハンドルの場合、解放されているかどうか(nullチェック)で、
生死を判断していました。
結局、この生死判定をフラグに置き換える必要があります。
そうしないと、死んでいても永久に生きているように振舞うので。
まあ、そう考えると、結局 null チェックが、
フラグチェックに変わるだけなのかー。
面倒なのは変わんないんじゃね?

ともかく、
とりあえず両者とも、ぼちぼち試して見たいと思いまする。

[ Delphi ]

2006年04月22日

[Delphi] ハンドル改善案(妄想編)

もうDelphiにマクロがあったら、くらいしか思いつきません。

macro IfAssignedDo(Object; Method);
begin
  if Assigned(Object) then
    Object.Method;
end;

で、

IfAssignedDo(TChild(FChildHandle.ToObject), Attack);

まあ、実際にはできませんので……。
妄想文法にて失礼いたします。

[ Delphi ]

2006年04月21日

[Delphi] ハンドル改善案2

思いついた案。無理やり、

type TObjectProcedure = procedure of object;
procedure IfAssignedDo(Obj: TObject; Proc: Pointer);
var Method: TMethod;
begin
  if Assigned(Obj) then begin
    Method.Code := Proc;
    Method.Data := Obj;
    TObjectProcedure(Method);
  end;
end;

って、定義しておいて、

IfAssignedDo(FChildHandle.ToObject, @THoge.Attack);

というのも考えました。
が、ポリモフィズム(多態)できてないじゃん!ってことで、×。

前回で失敗した仮想関数でも、Self = nil になるのなら、

procedure IfAssignedDo(Proc: TObjectProcedure);
var Method: TMethod;
begin
  Method := TMethod(Proc);
  if Assigned(Method.Data) then
    Proc;
end;

として、

IfAssignedDo(TChild(FChildHandle.ToObject).Attack);

って書けるのになー。(できませんので)

続かない予感。(イヤだってもうマクロでもない限り無理ぽ

[ Delphi ]

2006年04月19日

[Delphi] ハンドル利用の改善案

ハンドルをいかに面倒なく扱うかという問題。

視点を変えてみます。
nullが帰って来るなら、nullでメソッドを読み出しても大丈夫にすればよいのかな?と。

そこで導入するのは、
Null Objectパターンならぬ、Null Object Methodパターン(勝手に命名
Delphiの場合、オブジェクトの参照が null でメソッドが呼ばれた場合、Selfが nilになることを生かします。
つまり前回の例だと、

procedure TChild.Attack;
begin
  if Self = nil then Exit;
  { 適当な処理 }
end;

としておくと、
null が Attackを呼び出しても何もしないので、

TChild(FChildHandle.ToObject).Attack;

と一行で書ける訳です。
ちなみに、キャストがうざい、という話には、Delphiのジェネリック対応が必要ですな(無理

……と思ってたけど、駄目じゃーーーーーーん。
メソッドが(Attack; ) が 仮想関数(virtual や override)だと駄目でしたー。
やってはいけません。

続く。
……予定だっけど続かなくなりそうな悪寒。

[ Delphi ]

2006年04月18日

[Delphi] ハンドル不満点

ハンドルの不満点とは。
前回の例でもわかるのですが、とにかく面倒なところです。
冗長なんですね。

FChild.Attack;

と一行ですむところを、

procedure ChildAttack;
var Child: TChild;
begin
  Child := TChild(FChildHandle.ToObject);
  if Assigned(Child) then  // ← Child <> nil と同じ
    Child.Attack;
end;

// どこかで
ChildAttack;

と何行にもわたって書かなくてはいけません。
呼び出すのが Attack だけならいいのですが、
他のメソッドも呼びたい場合には、そのつど

  • ハンドルからポインタに変換
  • nullチェック
  • メソッド呼び出し

と、する必要があります。

しかも、ChildAttack; って、オブジェクト指向っぽくないし。

はっきりいって面倒です。
これをなんとか簡単にする方法は……。

続く。

[ Delphi ]

2006年04月17日

[Delphi] ハンドル

ゲームプログラミングでは、
ポインタを生で使うと危険な場合が往々にあります。

例えば、多パーツの親オブジェクトと子オブジェクト。
ポインタなどでお互いを参照している場合、
片方が消えている(解放されている)と、不正なアクセスになりかねません。
多くの場合、死亡フラグを立てて、1フレーム遅れて開放したりするのですが、それでもタイミングによっては、不正なアクセスを起こすことになります。

そこで導入するのが、ハンドルの概念です。
詳しくは、Game Programing Gemsを参照……、というのはアレなんで、
コードで説明すると。

子オブジェクトに攻撃命令(Attack)を出す例。

FChild.Attack; // ←FChild が 解放されている可能性があり危険!

これは×。

if FChild <> nil then  // ←他の場所で解放されていると、
  FChild.Attack;       // nullでない可能性があり、解決策になってない

これも×。

直接参照を呼ぶのではなく、一旦、ハンドルを介します。

var Child: TChild;
begin
  Child := TChild(FChildHandle.ToObject);
  if Child <> nil then
    FChild.Attack;
end;

これは○。
つまり、ハンドルは「他で解放されるとちゃんと null を返すもの」ということです。
# ここでは、ハンドルの内部実装はおいておいて……

こんな便利なものですが、やはりというかなんと言うか、
不満点があります。

続く。

[ Delphi ]

2006年04月13日

[Delphi] Delphiイライラ(無名関数くれ)

前回に引き続いて、ブロックもいいけど、無名関数でもいいので、それも書いてみようと思う。

for i := 0 to FItems.Count - 1 do begin
  Part := Items[i];
  if Part.IsExistence then
    Part.Move;
end;
 
for i := 0 to FItems.Count - 1 do begin
  Part := Items[i];
  if Part.IsExistence then
    Part.Draw;
end;

は、

procedure THogeItems.Each(Func: TEachFunction);
begin
  for i := 0 to FItems.Count - 1 do begin
    Part := Items[i];
    if Part.IsExistence then
      Func(Part);
  end;
end;
 
Items.Each(procedure(Part); begin Part.Move; end);
Items.Each(procedure(Part); begin Part.Draw; end);

と書ける。ちょっとキモイ?

あとは、

Hoge.BeginXyzzy;
try
  Hoge.Mage;
  Hoge.MogeMage;
    :
finally
  Hoge.FinishXyzzy;
end

は、

procedure THoge.Xyzzy(Func: TXyzzyFunction);
begin
  BeginHoge;
  try
    Func;
  finally
    FinishHoge;
  end;
end;

Hoge.Xyzzy(procedure; 
begin
  Hoge.Mage;
  Hoge.MogeMage;
  :
end;);

やっぱり、procedure;とか、突然括弧来るのがちょっとキモイ。
Pascalを保ったまま、しっくりくるいい文法案ないかな。

以上、俺Delphi言語案でした。

[ Delphi ]

2006年04月12日

[Delphi] ああ、Delphiイライラ(ブロックくれ)

だめだ!Delphiにもブロック構文ほしすぎる。
無名関数でもいいからくれ。
高階関数すらマンドクサくなってるよ、もー。

ブロックがあれば、圧倒的に簡潔に書ける部分がちらほらでてくると、
イライラしてきます。Ruby病。

例えば定型のループ処理(イテレート処理)なんかは、
ブロックあれば、超楽になる。

for i := 0 to FItems.Count - 1 do begin
  Part := Items[i];
  if Part.IsExistence then
    Part.Move;
end;
 
for i := 0 to FItems.Count - 1 do begin
  Part := Items[i];
  if Part.IsExistence then
    Part.Draw;
end;

なんての単調なのも、(ブロックがあるとすると)

procedure THogeItems.Each;
begin
  for i := 0 to FItems.Count - 1 do begin
    Part := Items[i];
    if Part.IsExistence then
      Yield(Part);
  end;
end;
 
Items.Each do begin |Part| Part.Move; end
Items.Each do begin |Part| Part.Draw; end

でよい。(これでもまだ単調だけど)

最近のDelphiの新機能、for-in-doでもできるけど、
イテレータ(Enumerator)の用意が面倒すぎる。

あとは、try-finally-end を多用するところも、
ブロックで省略できる。

Hoge.BeginXyzzy;
try
  Hoge.Mage;
  Hoge.MogeMage;
    :
finally
  Hoge.FinishXyzzy;
end

と何度も書くのを、

procedure THoge.Xyzzy();
begin
  BeginHoge;
  try
    Yield;
  finally
    FinishHoge;
  end;
end;

Hoge.Xyzzy do begin
  Hoge.Mage;
  Hoge.MogeMage;
  :
end;

でOK。行数増えたけど、何度も書くときは、後者の方が楽。
というか、Finallyすることを強制できる。

しばらくは、高階関数と for-in-do で我慢するしかないかなー。

以上、俺Delphi妄想案でした。

[ Delphi ]

2006年04月09日

[Delphi] リファクタリングエラーが……('A`)

なんだか、BDS(Borland Development Studio)のリファクタリングで、
エラーが起きることが多くなってまいりました。

常用の「名前の変更」リファクタリング機能なんですが、
「リファクタリングをセットアップできませんでした」
とか言われて、進まない。
こりゃ困った……。

Borlandに報告したいけど、
20万行くらいのコードだから、切り出しがメンドイ……。

実験してみた結果、
overloadした関数(同じ名前の関数)があると、エラーが起きやすい?模様。
片方のoverload関数を、一旦別の名前に置換すると、エラーが起きなかった。

エラーの起こった1ユニットだけ切り出しても、再現しないっぽい。
と思ったけど、違う意味でマズイ。片方のoveerload関数を変更したら、
もう片方の関数もご認識して、置換してる。アワワワ。
まあ、1ユニットだけ取り出した、コンパイルが通らないコードだからだろうけど。

しかし、報告するには曖昧だなー。
全部のコード出すわけにもなあ。
むむむ。

[ Delphi ]

2006年04月06日

[Delphi] FastMMの威力

Delphi2006では、メモリマネージャが FastMM という速いものに
置き換わっているというので試してみました。
コードはこんな感じ。
とりあえず、メモリ確保するだけの処理。

program SpeedCheck;

{$APPTYPE CONSOLE}
uses SysUtils;
type
  TTest = class
    FMoge: Integer;
    procedure Hoge;
  end;
{ TTest }
procedure TTest.Hoge;
begin end;
const
  NumOfLoop = 10000000;
var
  i: Integer;
  Test: TTest;
begin
  for i := 0 to NumOfLoop - 1 do begin
    Test := TTest.Create;
    Test.Free;
  end;
end.

Delphi6の場合、

> time SpeedCheck_Delphi6.exe
real    0m3.131s
user    0m0.046s
sys     0m0.046s

Delphi2006の場合、

> time SpeedCheck_Delphi2006.exe

real    0m1.622s
user    0m0.031s
sys     0m0.015s

ちょwwこれはwww
約2倍はやくなってるーーーーーーーwwwww
すげーwwww

まあ、小さいメモリブロックは、再確保しないようになってるらしいから、
そのせいでしょうな。
中規模、大規模の確保も後で試してみよう。

FastMMは、フリーソフト(MPL)で、
他のバージョンでも入れられるようなので、
Delphi2006でない方も導入してみたらどうでしょう。

FastMM導入はこちらが参考になります
FastMMの仕組みについてはこちら

[ Delphi ]

2006年04月05日

[Delphi] リファクタリング機能が便利するぎる件について

今更ながら、Delphi2005から搭載された
リファクタリング機能が便利すぎると感じています。

一番よく使うのが「名前の変更」。

例えば、関数名に「名前の変更」を使うと……。

  • インターフェスの関数名(procedure Hoge;)
  • 実装の関数名(procedure Hoge; begin end;)
  • 参照されている関数名(Hoge;)

全て一発で修正してくれます。
リファクタリング好きにはたまりませんなあ。

惜しい点としては、

  • 「名前の変更」は、構造体の定数には使えない
  • 「名前の変更」はあっても、「型名の変更」がない
  • 「メンバの移動」は、普通の関数には使えない
  • 「パラメータの変更」は、既存のパラメータの編集ができない
  • 全体的に、クラスが中心で、関数型プログラミングには向いてない

惜しいというかほしい機能だったりする。

[ Delphi ]

2006年03月26日

[Delphi] class helper

今、話題(2chのDelphiスレだけで)の class helper 使ってみました。

ruby だと

class String
  def increment
    result = "";
    self.each_byte do |c|
      result << (c + 1).chr
    end
    result
  end
end

p "HAL".increment

という風に書くのを、Delphi で書くと、

program test;

{$APPTYPE CONSOLE}
uses SysUtils, Classes;
type
  TMyClassHelper = class helper for TStringStream
    function Increment: string;
  end;

{ TMyClassHelper }
function TMyClassHelper.Increment: string;
var i: Integer;
begin
  Result := '';
  for i := 1 to Length(DataString) do
    Result := Result + Char(Ord(DataString[i]) + 1);
end;

procedure Main;
var s: TStringStream;
begin
  s := TStringStream.Create('HAL');
  try
    Writeln(s.Increment);
  finally
    s.Free
  end;
end;

begin
  Main;
  {$WARN SYMBOL_PLATFORM OFF} if DebugHook <> 0 then Readln; {$WARN SYMBOL_PLATFORM ON}
end.

となる。
(stringがクラスじゃないので、TStringStreamで代用……)

これって、Mixinじゃない?
下手すると変なコードを量産しそうだけど、
使いようによっては、かなり使えるんじゃないんだろか?

あと、よく考えたら、アスペクト指向的にも使えね?

program test;

{$APPTYPE CONSOLE}
uses SysUtils, Classes;
type
  TStringList = class helper for TStringList
    function Add(const S: string): Integer;
  end;

{ TMyClassHelper }
function TMyClassHelper.Add(const S: string): Integer;
begin
  Writeln('start - TStringList.Add(' + S + ')');
  Result := inherited Add(S);
  Writeln('end - TStringList.Add');
end;

procedure Main;
var s: TStringList;
begin
  s := TStringList.Create;
  try
    s.Add('Hoge');
    s.Add('Moge');
    s.Add('Mage');
    Writeln('Count = ', s.Count);
  finally
    s.Free
  end;
end;

begin
  Main;
  {$WARN SYMBOL_PLATFORM OFF} if DebugHook <> 0 then Readln; {$WARN SYMBOL_PLATFORM ON}
end.

出力結果は以下。

start - TStringList.Add(Hoge)
end - TStringList.Add
start - TStringList.Add(Moge)
end - TStringList.Add
start - TStringList.Add(Mage)
end - TStringList.Add
Count = 3

ちょwww!?これはっwww
なんだか、脳汁が出てきましたよwww!?

とりあえず、標準出力にデバッグ文出してるだけだけど、
関数の実行時間を測ったり、用途はいろいろありますなー。

ヘルプに書いてある、
『ただし,ソースコード内の特定の場所では,最大 1 つのクラスヘルパーだけが適用されます。』
というのがなんだか、(´・ω・`)ショボーン 。
複数のクラスヘルパー適用できないのかい!
って、実は使えなさげな雰囲気もかもしだしておりますが、
class helperは、面白そうな機能であることは確かです。

[ Delphi ]

2006年03月07日

[Delphi, Ruby] rubyを組み込みたい!

便利で便利なスクリプト言語ruby。
アプリに組み込んだらハッピーじゃない?
ネット関連とか、文字列処理もそうだし、あとライブラリが豊富。
# webからrssとってきて、パースとか一瞬でできる
GUIは苦手だから、Delphiで補う。
というわけで、ruby + Delphi = 最強じゃまいか!計画進行中。

しかし、ちょっとした弊害が……。
ruby-mswin32 に付属のDLLを使えばすぐにでも使えそうなんだけれども、
実はライセンスがGPLだということ。
# ruby は GPL とアーティスティックラインセンスのディアルライセンスなのだが、
# ruby-mswin32 に限っては、配布者の考えで GPL になっている。
オーマイガー。
GPL感染だけは勘弁な。

指針としては、怪しいLGPLな正規表現周りのコードを、
ライセンスクリーンな鬼車に置き換えて、
クリーンにしればおk?

ということで、自前でソースからコンパイルしておりまする!ずずずいと!
ああ!でもコンパイル作業がエラーで止まるぞ!minirubyが落ちるぞ!
前途多難!どうしたもんじゃ!

# 眠剤x2飲んで書いた文章につき、このようになっております

[ Delphi , Ruby ]

2006年02月09日

[Delphi] ドナ ドナ ドーナ ドーナ Delphiを乗せて~

DelphiやらC++Builderが、売られるとか売られないとか(´д`;)
自分が愛してやまないDelphiがこんなことになるとは……。

BDS2006(Borland Development Studio)でようやくまともになったと思ったのになあ。
まあ、確かに最近のBorlandはハズしまくりの感はあったけど。
(Kylix、Delphi8、C#Builderなど)

しかし、処理系とIDEがほしくて、継続的に開発できるパワー(資金、人)を
持っているところはどこだろう?

MS Delphi?
Microsoftは、VisualStudioがあるから、うまみがないしなあ。
すでに、Delphi開発者のヘジルスバグ氏も手に入れてるし。

Open Delphi?
オープンソースは資金面でありえないか。

はてな Delphi?
いや、ないか。面白いけど。

ソースネクスト Delphi
1980円で販売。

livedoor Delphi?
目指すは yahooなライブドアにはないか。

google Delphi?
本命?処理系とかほしそうだし。

あとは、IBM Delphi とか Sun Delphi(Sunはありえねー)。

大穴で、Digital Mars Delphiとか。(ないか)

[ Delphi ]

2006年01月13日

[Delphi] 続・Delphiでクロージャ

クロージャで紹介したサイトにトラックバックを送ったら、
使い方を教えてくださいました

以前に、Delphiで高階関数やるをやってたので、大体わかりますた。

これの便利さは身に染みてたりします。
mapをコレクションクラスに実装して、
for 文なんておさらばだぜーとかやってました。

しかし、クロージャ版でやると、スマートにかけそうです。
こりゃ、便利じゃないすか?

欠点としては、複数の引数を受け渡すときに、レコード書くのマンドクセ('A`)
といったところでしょうか。

以下、テストコード

続きを読む "[Delphi] 続・Delphiでクロージャ" »

[ Delphi ]

2006年01月11日

[Delphi] Delphiでクロージャ!

Delphiでクロージャをやっておられる方が!
って、クロージャ使ったことないので、いまいち利便性がわからないけど(ぉ
Lisp使いだと楽勝なんでしょうけど。
# Rubyにもあったっけ?

ローカル変数を外に持ち出せる……。
面白そうではあるんですが……。

[ Delphi ]

2005年12月23日

[Delphi] Delphi2006キター

BDS2006

Borland Developer Studio 2006(Delphi 2006)が到着いたしました!
ちょwwお前、買わないじゃなかったのかwwという突っ込みは、以下略

外装は、前(Delphi2005)と同じなので写真は、省略します。

前のDelphi2005をアンインストールして、いざ、インストール。
掛かった時間は、大体45分くらい。思ったより速い。

さて、問題の起動時間は、Pen4 2.6Gで、1分ちょい。
おお!前よりかなり速い気がします。
Win32モードのみで起動とかできるけど、時間は大して変わりませんでした。

エディタも適当に触ってくらいでは、固まりませんでした。

リファクタリング機能は、やはり重いです。
メモリをあっと言う間に、100Mくらい持っていく事も。
手で直した方が速いなあ。使い気おきないっす。

コンパイル速度は、25万行のプロジェクト(顔!顔!顔!)の再構築で、
たった10秒と相変わらず爆速。
# 最初、OggVorbisのファイルがコンパイル出来ずにあせったけど。
# Palloc_chain = ^palloc_chain
# とか書いてました。何で今までこれ通ってたのよ……。

ヘルプは相変わらず重いです。

モデルビュー

モデルビュー(Togher)は、面白いなあ。
コードから自動でUML図を生成。
もちろん、UML図を編集可能。
初めて触りました。前にも付いてましたっけ?

強化されたコードテンプレート等は、後ほど。

ファーストインプレッションは、かなり好感触。
起動時間と、エディタのフリーズ問題は、やる気に直結するので、
まあ、これだけでもよかったかもしれない。
ただ、3万も掛かるアプグレードはタカス!

とりあえず、後はメインのプア環境でまともに動くかどうかなんだけど……。
期待はしない方がよさげ……。

[ Delphi ]

2005年12月05日

[Delphi] Delphi2005→Delphi6

Delphi_2005_12_05.jpg

Delphi2005なんですが、
重いし、固まるし、無限ダイアログエラー出るわで、
もう怒って、Delphi6の方に戻ってきました。

ソースコードもダウングレード。
for-in-do とか、クラス内宣言とか、
けっこうDelphi2005の拡張を使ってあって苦労しました。

3歩進んで、2歩下がってきた感じ……。

ちなみに、Delphi2006の販売案内が来てました。
IDEが安定してて、軽くなったなら即買うんですけど。
ただ、推奨メモリ1GBって書いてあるのが……orz。
しかし、せっかく、演算子オーバーロードができるようになるというのに、これではー。

Delphi6,7並みに軽くて、拡張されたコンパイラが使えるIDEキボンヌ(無いから
# この際、Lazarusに逃げるのは無し

[ Delphi ]

2005年06月03日

[Delphi, 開発] 今日のハマリ

procedure Moge(var Hoge: THoge);
begin
  FreeAndNil(Hoge);
  Hoge := THoge.Create;
  :
end;
 
procedure Xyzzy;
var 
  Hoge: THoge;
begin
  Moge(Hoge);
  :
end;

Xyzzyのローカル変数Hogeが初期化されていない(=適当な数値)ので、
Moge呼び出し時に、FreeAndNilでどこかのメモリを破壊。
この後、関係のないところでアクセス違反が起きる、という凶悪なコード。

で、正しくは、初期化してやればいいので、こう書く。

procedure Xyzzy;
var 
  Hoge: THoge;
begin
  Hoge := nil;  // ←ここを追加した
  Moge(Hoge);
  :
end;

……コンパイラさん、参照渡しするときにローカル変数を初期化してないっつー、
エラーくらい吐いて下さいよー、だめ?
実は、最初、ちょうど、for-in-do周りでアクセス違反が起きたから、

 ま た 、 f o r - i n - d o か !

とか、思ったので、もうマジで頼む。

この際、Moge自体がアレ(つまり、オイラ自身が(げふんげふん))だということは棚に上げます。
コンパイラができることは、できるだけ、コンパイラがやるべきだと思うので。

そういえば、JAVAだと、そもそも副作用が怖いのか、
参照渡し(Delphiのvar引数)がないんだよねー。
そういう割り切り方もありだと思う。

[ Delphi , 開発 ]

2005年05月23日

[Delphi, 開発] 今日のはまり

固定小数点の罠

var MinValue: TFixed;

MinValue := Double2Fixed(Low(Integer));

これで、MinValue が適当に最小値になると思いきや……。

Double2Fixedの実装が、

function Double2Fixed(const Value: Double): TFixed;
begin
  Result.Value := Round(Value * 65536);
end;

Value * 65536 ……

Value * 6 5 5 3 6 ・ ・ ・ ・ ・ ・

V a l u e * 6 5 5 3 6 ・ ・ ・ ・ ・ ・
(もういい)

Round(Low(Integer) * 65536) = 明らかにアンダーフローなわけですね。

もう固定小数点(古い遺産)いやだー。
浮動小数点に全書き換えしようかな……。

[ Delphi , 開発 ]

2005年05月15日

[Delphi, 開発] for-in-do バグ調査 at Delphi2005

※このバグは、Delphi2006では修正済みのようです

腹が立ったので、その後、調査してました。
再起動しまくりながら、ようやく、
バグらせる最小限のコードを見出せました。

肝は、Enumeratorのコード。
下記にバグらせるコード出しときます。

TTestEnumerator = class
private
  FCurrentItem: Integer;
public
  constructor Create(list: TTest);
  function MoveNext: Boolean;
  property Current: Integer read FCurrentItem;
end;

↓だとOK。

TTestEnumerator = class
public
  function GetCurrent: Integer;
  constructor Create(list: TTest);
  function MoveNext: Boolean;
  property Current: Integer read GetCurrent;
end;

こんだけかよ!

こんだけです。
ヘルプには、

GetEnumerator() が返すクラス,インターフェース,レコードには Current というパブリックインスタンス読み出し専用プロパティが含まれている必要があります。Current プロパティの型は,コレクションに含まれる型である必要があります。

とあるので、仕様的には、propertyに関数じゃなくて、
フィールドを入れても問題ないはず。
とりあえず、回避策はわかったのでよしとします。
ちなみに、入力不能になるのは、何故か、
for-in-do呼び出し側が「書込み禁止」になるからです。謎。

[ Delphi , 開発 ]

2005年05月13日

[Delphi, 開発] for-in-do at Delphi2005

Delphi2005の新機能 for-in-do。
使ってなかったけど、これってすんごい便利じゃないのだろうか。

前は、

for i := Low(ArrayData) to High(ArrayData) do 
  Writeln(ArrayData[i]);

とかやってたけど、

for i in ArrayData do 
  Writeln(i);

で、いいのか!
他の言語で言えば、foreach構文ですな。

自分で作ったクラスにも特定のメソッドを追加すれば、for-in-do対応にできるし、
こりゃ、地味に便利だ。
ていうか、今頃気づくなっつーの。

この調子で次期バージョンに新機能をバンバン追加してくれたら、
他の言語に目移りしないですむのになー。
(なんか、最近、C#とかD言語に誘惑されまくり)
次は、無名関数くれくれ。

とりあえずは、自前コンテナクラスを for-in-do 対応にしとこう。

……と思ったら!
自前のクラスだと、IDEでアクセス違反がでて、
コンパイルすらできないじゃないか!!
(2つの環境で確認。.NET切り離した環境だと、エディタに入力すらできなくなって再起動必須)
どないせいちゅーんじゃー。

[ Delphi , 開発 ]

2005年05月02日

[Delphi, GAN GAN GAN, 開発] XMLを簡単に扱おう

ここ何日間はXML読み書き周りの整理。

OpenXML for Delphi用の簡単にXMLを扱うクラスを作ってみた
こんな風に使える。

書き込み例:

<moge>   <hage>1234</hage>   <hoge>ha-ge</hoge>   <hoge>True</hoge> </moge>

上記データを書き込む場合。

uses O3EasyXMLUnit; : XML := TO3EasyXMLWriter; try   XML.BeginElement('moge');   try     XML.Write('hage', 1234);     XML.Write('hoge, 'ha-ge');'     XML.Write('hoge, True);   finally     XML.EndElement;   end;    XML.WriteToFile('hoge.xml'); finally   FreeAndNil(XML) end;

読み込み例:

<moge>   <hage>1234</hage>   <hoge>ha-ge</hoge>   <hoge>xyzzy</hoge> </moge>

上記データを読み込む場合。

uses D3UtilsUnit;    procedure THoge.FogeMoge; var XML: TO3EasyXMLReader;      procedure DoEnumFunction(const index: Integer); cdecl;   begin     FList.Add(XML.Read());   end; begin   XML := TO3EasyXMLReader;   try     XML.LoadFromFile('hoge.xml');     XML.BeginElement('moge');        try       IntValue := XML.Read('hage');       Enum('hoge', TDoEnumFunction(@DoEnumFunction), D3GetContext);     finally       XML.EndElement;     end;   finally     FreeAndNil(XML);   end; end;


Enumら辺は高階関数を利用。
気持ち悪い人用に、一応、メソッドポインタもサポート。
普通の関数呼び出しもできるので、宣言が面倒なメソッドポインタはサポートしない方向で。


サポートは、例のごとくwikiの方で

[ Delphi , GAN GAN GAN , 開発 ]

2005年02月13日

[Delphi] Delphi2005 その4

1ヶ月ほど使ってみた結果……。

いいところ追加


  • しおりの位置がDelphiを終了しても、保存されている
    これはいい。素晴らすぃ。

悪いところ追加


  • エディタのタブが多段にできない
    以前は、GExpertsで多段にできたのだが……。

  • コード補完、引数表示不能。
    「"UriUtils.pas"ユニットはコンパイルできませんでした」と言われる。

  • 終了時に、エラーがでる。
    家だと出ない。どうも学校の環境だと激しく不安定。

あ……と、パッチ当てたら、
「コード補完、引数表示不能。」ってのは直った。
使えなきゃ、統合環境の意味ないんだけどね。

[ Delphi ]

2004年12月16日

[Delphi, 開発] Delphi2005その3

大学のプアマシン(Cerelon 1.2GHz, 512MB)にインストールしたら、
インストールだけで4時間かかった。
起動には4分。

さらにいざプログラム組もうとすると、エディタが張り付く。
property と入力しようとして、
pを入れた瞬間に1分待たされ、
proの時点で1分待たされ、
propで1分待たされ、
proprと間違えて入力してBS押すと1分待たされ
(以下略)

もうだめぽ。
タスクマネージャで見たらメモリ400MB以上食ってるし……。

    マシンを買い換える
にア Delphi6にもどす

というわけで、しばらくはDelphi6(学校)と2005(家)の両方を使うことになりそう。

と、思っていたら、YT先生が.NETパッケージをはずしたり、つけたりするツールを作ってくださいました

やったー、起動4分が、3分30秒になったよー(←ここ、_| ̄|○するところ)
で、実は、エディタの張り付きがなくなり、
Delphi6使わなくてもよくなったという。
よしよし。

あと、感想の追加。

良い点追加。


  • IDEのアイコンがアレキサンダー(?)

  • 地味に、エディタの色設定で自由に色が変更可能
    前は、限られた色だけだった

  • オープン配列を持つ関数の引数内で、コード補間が効く

悪い点追加。


  • Ctrl+F12のユニットの表示が改悪された
    例えば、普通の.pasファイルは選択できるが、
    テキストファイルのようなものは候補に入らず選択できない

  • フリーカーソルなのだが、動作が変。
    日本語が入った行で、行末以降にカーソルを持って行き、
    上下移動するとカーソルが左右にぶれる

  • 家の環境で、2005インストール当初Delphi6が起動しなくなったいた
    今はなんとか大丈夫。何故、起動するようになったかは謎。

  • やっぱりたまにコード補間が効かなくなる


んー。
やはり、この人柱全開ぷりがたまらん。

[ Delphi , 開発 ]

2004年12月12日

[Delphi, 開発] Delphi2005続き

Delphi2005

全体的にVisualStudioっぽくなっている。
コンポーネントパレットはなくなっているし。

しかし、どうももっさりしている。
まず、前にも書いたが、起動が遅い。
ページを切り替えるたびに数秒待たされる。
コードを入力するたびに、数秒またされる。
リファクタリングの前準備に、スワップ→数分経過とか……。

これは、明らかにスペックが足りていない。
使用メモリは、余裕で250MBytes近くいく。
足りないのはメモリー容量(ギガは欲しい……)と、後はHDDの速度だなー。
メモリー増設決定じゃー。

いい所


  • リファクタリング機能が便利

  • ヘルプが新型になっている(.hlpじゃない)

  • Win32も.NETでも開発できる

  • さらに、C#で開発できる(!)

  • 地味にショートカットがしっかり割り当ててあって、拡張ツールのGExpertsでほとんど再割り当てしなくてすむ。
    「全保存」や「再構築」、「ファイルの検索」とか。

  • デバッグなしで実行できるモードがある。
    今までは、デバッグオプションで一々切り替えていた。
    Ctrl+Shift+Dに表示を割り当ててはいたが。

不満点


  • メモリを食いすぎ

  • 簡単にコンポーネントを追加できない

  • パッケージ作ってからやるしかない?
  • バージョン管理は自前でやるから、中途半端なヒストリ機能などいらない。
    つか、.historyフォルダ勝手に作るのウザイ。

  • エラー箇所をエディタ上で表示するErrorInsightは、誤爆しすぎて全く使えない

  • Undoが Ctrl+Z を2回押さないと働かない時がある

  • 同様に、Redoが効いたり効かなくなったり

  • ヘルプに若干不備がある
    ていうか、キーボードショートカット見ようとしたらいきなり見れねえし

  • genericまだぁ?

  • 関数内関数のポインタはいつになったら利用できるのか?もっと楽にlambdaりたい。

で、パッチはいつでる?(ぉぃ


開発中のゲーム「顔!顔!顔!」のコンパイルは、
最初、通らなくてひどくあせった。
単に引数のカンマが抜けていただけだったが、
コンパイルドユニットのせいで
たまたま以前の環境ではエラーをすり抜けていたと言うオチ。
# 再構築すると発覚するわけ

[ Delphi , 開発 ]

2004年12月11日

[Delphi, 開発] Delphi2005キター!!

外装

さあ!待望のDelphi2005が到着いたしました!!

何故か、シンガポールより国際郵便にて直送であります。
海外で作った方が安上がるからでありますか。
徹底したコスト削減でありますね。

どうでもいいけど、郵便の名前がものすごい出鱈目であります。
いや、珍しい名前だから慣れてはいますが、これはちょっと。

内装

さて、いよいよ開封した後、まずはパッケージにプチ感動。
カッコイイ!
折りたたみ式の内装も生かす!

で、いよいよ、インストール!

起動スプラッシュ

そして、ファーストインプレッション。

 起 動 が 遅 い … … 。

Delphi6と比べ、当社比、2倍。
# 2.6GHz, 512MBで約1分
起動しておいて、裏でネットうろついて、気が付いたら起動。

DiamondBackは地獄だぜ

もうこれだけで、ご飯、3杯食えるくらい。

そうそう、いきなりイースターエッグ発見、バージョン情報ダイアログで、
ALT押しながら、TEAMと入力すると……。
くだらね。いや別にやらんでいい。

肝心の新しくなったIDE、新機能等は、
おって報告いたす。

[ Delphi , 開発 ]

2004年12月07日

[Delphi, 開発] ヘジルスバーグたんハァハァ

Hejlsberg00.png

実は自分は、大のヘジルスバーグファンである。
え?誰かって?
では簡単に説明しよう。

アンダース・ヘジルスバーグ(Anders Hejlsberg)とは、
Borland TurboPascalの開発者であり、Delphiの生みの親。
Delphi for Javaを設計するも世には出なかった。
1996年にBorladをやめ、MSに引き抜かれ、VJ++を設計。
その後、今流行のC#を設計した。
Borlandを離れた今でも、根強い信者が少なくない人である。
ちなみに、MSからの報酬として300万$(約3億3千万円)のボーナスをもらったという。
# 流行のストックオプションというやつらしい

写真は、Delphi1のバージョン情報表示から見られる写真である。

標準化などいざしらず、独自仕様万歳主義、実用優先主義は、
自分も影響を受けていないとはいえない(ホントかよ)。

そうそう、C#はよくJavaのパクりだ、と言われるがそうじゃない。
彼の経歴を見るに、Delphi + J++ なのだ。

[ Delphi , 開発 ]

Twitter(今何してる?)

プロフィール

あわせて読みたい

あわせて読みたいブログパーツ

人気エントリー

About Delphi

ブログ「第一種臨界不測日記」のカテゴリ「Delphi」に投稿されたすべてのエントリーのアーカイブのページです。過去のものから新しいものへ順番に並んでいます。

前のカテゴリはC#です。

次のカテゴリはD言語です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。