Apr 2006
XOOPS 2.0.14 JP リリース
XOOPS 2.0.14 JP 正式版がリリースされました。これは先週リリースされたRC1とほとんど変わりはありませんが、ひとつのバグが修正されています。これにより PHP 5.1.x でも問題なくインストールが可能になりました。

おそらく 2.0.14 XOOPS Cube Project における 2.0.x 系の最終バージョンになるでしょう。開発チームは、しばらくの期間、重大なセキュリティ問題へのカバーを続けますが、 XOOPS JP シリーズより XOOPS Cube シリーズを推奨することになります。
|
XOOPS 2.0.14 JP RC1 リリース
XOOPS Cube 開発チームによる 2.0.x 系である XOOPS 2.0.14 JP RC1 がリリースされました。このバージョンでは大部分のNOTICE(参照に関する仕様変更によって発生するPHPの警告)がonokazuさんの頑張りで取り除かれたほか、3rdライブラリのバージョンをアップデートしています。ただ、開発チームはXOOPS Cube 2.1系に注力しているため、このバージョンのチェックは多くのユーザーの手助けを必要としています。

2.0.14 JP RC1 をインストールして、もしバグかNOTICEを見つけたら公式サイト等へ報告してください。もしRC1が大きな問題を持っていなければ、一週間後に公式リリースを行います。
|
真のDbC
先日までのエントリで、C++によるシンプルなDbCを理解することができたと思います。しかし、本当のDbCにはもっと強力な特徴があります。再現にあたり注意を払うべきDbCの特徴は以下です。

  • クラス不変条件は継承されます。派生クラスの不変条件は基底クラスの不変条件を暗黙的に呼び出します。
  • クラス階層のメンバ関数において、派生クラスのメンバ関数の事前条件は、すべてのオーバーライド関数の事前条件とORされます。事後条件はANDされます。

(日本語訳においてこちらのページを参考・引用)

言い換えれば、DbCはクラス会層に対して特別な動作を行います。クラス不変条件の継承を実現するために、基底クラスの不変条件を呼び出すように派生クラスを記述しなければなりません。例のページには次のようなコードが示されています:

void A::foo()
{
    
check_invariant(*this);
    ...
    
check_invariant(*this);
}

// B.h:

#include "A.h"

class B : public A {
    
public:
#ifdef DBG
    
virtual void invariant()
    {   ...
contracts...
       
A::invariant();
    }
#endif
       
void bar();
};


事前条件と事後に関して、メンバ関数内部で基底クラスの該当条件チェックを呼ぶコードを記述すべきです。 しかし、深いクラスでは、すべての条件を呼ばなければならないため、それは非常に複雑になるでしょう。

class B : A
{
protected:
    
#if DBC
    
int foo_preconditions() { ...Bpreconditions... }
    
void foo_postconditions() { ...Bpostconditions... }
    
#else
    
int foo_preconditions() { return 1; }
    
void foo_postconditions() { }
    
#endif

    
void foo_internal()
    {
    ...
implementation...
    }

public:
    
virtual void foo()
    {
    
assert(foo_preconditions() || A::foo_preconditions());
    
foo_internal();
    
A::foo_postconditions();
    
foo_postconditions();
    }
};


C++で事後条件を仕様(理想?)通りに実現することができるでしょうか? 恐らくそれは難しいでしょう。特に深い事前条件と事後条件はコードが複雑過ぎるため、使用に耐えないと思われます。しかし、実用(実益)レベルにおいて、これらのすべての仕様を実現させる必要があるかというとそうではなく、よく必要とする仕様だけを扱っても恩恵に預かれるはずです。本気で取り組むのであれば、プリプロセッサの開発が有効であると考えられます。
|
C++によるクラス不変条件
クラス不変条件はメソッドとして記述される一貫性チェックです。それは、関数の開始と終了時に呼び出されます。さっそく単純な不変条件を書いてみましょう。このところ毎回紹介しているこのページでは、以下のコードを示してます。

class A {
    
public:
#ifdef DBG
       
virtual void invariant() { ...contracts... }
#endif
       
void foo();
};

関数の内側で、invariant()を呼び出すコードを書かなくてはいけません。

void A::foo() {
#ifdef DBG
    
invariant();
#endif

    
...

#ifdef DBG
    
invariant();
#endif
}

例のページでは、マクロを含んだコールバックを設置するために、テンプレートを使うことを推奨しています。これはスマートな手段といえるでしょう。

template
inline void check_invariant
(T& iX)
{
#ifdef DBC
    
iX.invariant();
#endif
}

void A::foo()
{
    
check_invariant(*this);
    ...
    
check_invariant(*this);
}

単純な不変条件はこのように実現できます。しかし、D言語のDbcはもっと優れていますから、完全なDbCを現実のものにするためにはさらなる努力が必要となりそうです。
|
C++による事前・事後契約
それでは、標準C++におけるDbCの実現手段をひととりチェックしてみましょう。事前条件を実現するには、assertを関数の先頭部で使うことが有効であると、誰もが考えるでしょう。それは正解ですし、正しいassertの使い方といえます。

事後条件はどのようにするべきでしょうか。事後条件は関数の動作の終了後、端的に言えばreturnの後で実行されることが望ましく、関数の先頭に書きたいため、関数の終端にassertを入れるだけではDbCの性質をうまく実現することはできません。昨日紹介したこのページは、この課題についてデストラクタが有効であると回答しています。

void foo()
{
    
struct Sentry
    
{   Sentry() { ...preconditions... }
    ~
Sentry() { ...postconditions... }
    }
sentry;
    ...
implementation...
}


デストラクタはインスタンスがスコープを抜けた際にコールされますから、事後条件を関数の終了後にチェックできます。
|
標準C++におけるDbC
それでは、標準C++あるいは現場で使用しているC++環境ではどのように契約を書くべきでしょうか。多くのC++プログラマが挑戦している命題ですので、インターネットを検索すれば様々なサンプルを手に入れることができます。

皮肉なことに、もっともよい解決策のうちのひとつがD言語の公式サイトで示されています。これはD言語におけるDbCとC++のDbCを比較するページであり、D言語のDbCのほうが遙かに優れていると結論づけています。しかし、ここで示されているC++のコードは標準C++でDbCへの挑戦する非常によいヒントになるでしょう。このページは私たちにDbCの実現のためにはテンプレートなどC++の多くのテクニックを駆使しなければならないことを教えてくれます。

同様の試みは
Javaでも行われています。現実的な問題として、プログラミング言語がDbCを仕様として実装しなければ、C++JavaDbCを実現することは難しいといえるでしょう。しかし、DbCへの憧れは、assertの正しい使用への意識をもたらします。私たちはしばしばassertの重要性を忘れることがあるからです。
|
Digital Mars C++ Compiler
Digital Mars C++ Compiler DbC を実装した唯一の C++ コンパイラです。これはオープンソースプロジェクトではありませんが、無料で入手することができます。プログラマはこのコンパイラと共に契約を自然に書くことができます。

このコンパイラはD言語の開発者でもある Walter Bright 氏によって開発されました。D言語はこのコンパイラの開発経験をベースにしていると思われます。

では、このコンパイラと共にどのように契約を書くのでしょうか? それはD言語の構文と似ていますが、アンダースコアを接頭する必要があります
:

long square_root(long x)
    
__in
    
{
        
assert(x >= 0);
    }
    
__out (result)
    {
        
assert((result * result) == x);
    }
    
__body
    
{
        return
sqrt(x);
    }
|
契約の書き方
契約プログラミング(DbC)を実装するプログラム言語は、EiffelDigital Mars C++ CompilerとD言語などです。これらの言語はいずれも、現在決してポピュラーとは言えません。しかし、これらの言語で書かれた DbC を読むことによって、契約を書く方法や DbC の概念を理解することが容易になるでしょう。

D言語公式サイトのサンプルコードは、以下のようになっています:

long square_root(long x)
    
in
    
{
        
assert(x >= 0);
    }
    
out (result)
    {
        
assert((result * result) == x);
    }
    
body
    
{
        return
math.sqrt(x);
    }


in は、事前条件です。out は事後条件で、関数の戻り値である result 変数を得ることができます。

それぞれの条件チェックには
assert() を使用します。D言語の assert() は、例外 AssertException をスローするので、Cの assert() より役に立つと主張されています。例外であれば、キャッチした後、どのようにも取り扱いができるからです。
|
契約プログラミング
契約プログラミング Design by Contract (以下DbC) は、プログラミング言語 Eiffel Bertrand Meyer によって提起されました。それはプログラマが関数やメソッドに利用条件を書くことができるアサートの発展版といえます。契約は以下の条件から成ります:
  • 事前条件
  • 事後条件
  • 不変条件
これらの条件を満たさないケースでは、契約違反として、例外が投げられます。開発者は、例外によってプログラムの問題点を容易に見つけることができるでしょう。プログラマはソースコード上に関数などの仕様(利用条件)を直接記述して、アサートできるので、常に落ち着いて仕事を薦めることができます。

DbC は多くのプログラム言語で試みられています。標準C++では、事前条件は
assert() をうまく使うことができますが、しかし、事後条件と、不変条件の実現は難しいとされています。しかし、多くのプログラマが C++ で DbC に挑戦していますので、多くのサンプルコードをインターネットから手に入れることができるでしょう。
|