雲と遊ぼう

Object REXXの並列動作機能の感触を得るため、並列動作に依存する小さなシミュレーションプログラムを書いてみよう。雲のシミュレータである(実際、私がこのアイデアを得たのは窓の外の吹雪を見ていた時である)。CLOUD(雲)クラスを作り、これから雲の複数のインスタンスを生成して、それらの振る舞いをシミュレートする。

最初に思い付くのは、雲の次の属性だろう:

雲は大きさと温度で振る舞いを変える。小さな雲は全く雨を降らせない。中くらいの雲は多少雨を降らせる。大きな雲はどしゃ降りももたらす。雲の温度で、降るのが雨か雪か変わる。以上は現実の雲の正確な表現ではないけれど、ある程度の基本を押さえている。

雲の状態を変えるためにいくたリかのメソッドを実装しなければならない。現在の雲の状態(降雨中、降雪中など)も雲の属性に保存しなければならない。上記の仮定から、cloudクラスは以下の属性を必要とする:

雲の状態を変えるには、以下のメソッドが最低限必要である: 上記のメソッドは直接関係した属性(雲の大きさと温度)だけに影響を与えるのでなく、雲自体の状態にも関係する。ここで作る雲クラスは降雨を開始/停止する大きさ、豪雨/小雨を分ける大きさとして、雲ごとに異なった値をもつことができる。

ここまでの情報を総合すると、雲 cloud クラスの作成を始めることができる:


/**********************************************************/
/* Declare the cloud class. It will be a public class     */
/* that means it will be available to all REXX programs   */
/* referring to this program (e.g. by calling it).        */
/* cloudクラスをpublic (公開)クラスとして宣言する。public */
/* クラスは全てのREXXプログラムから参照可能になる         */
/**********************************************************/
::CLASS Cloud PUBLIC

/**********************************************************/
/* The INIT method of the cloud expects three arguments:  */
/* cloud クラスのINITメソッドは3つの引数をもつ:           */
/*   1. The name of the cloud 雲の名前                   */
/*   2. The initial size of the cloud 雲の大きさ         */
/*   3. The initial temperature of the cloud 雲の温度    */
/**********************************************************/
::METHOD INIT
  Expose Name Size ItsRaining HeavyRain
  Use Arg Name, InitialSize, InitialTemp

  /* set the attributes to their initial states           */
  Size = 0
  HeavyRain = .False
  ItsRaining = .False

  /* now let the cloud grow to the specified size         */
  /* 雲を指定の大きさにする                               */

  Self‾Grow(InitialSize)

  /* set the temperature of the cloud, this is done with  */
  /* a separate method that will set the rain/snow flag   */
  /* 雲の温度を設定する。これは降雨/降雪を切り換える他の  */
  /* メソッドと関係する                                   */

  Self‾Temperature = InitialTemp

  /* start another thread that will show us the rain      */
  /* 降雨を表示する別スレッドを起動する                   */

  Self‾ShowRain
grow(大きくする)、shrink(縮ませる)ルーチンは単に雲の属性を直接変える:

/**********************************************************/
/* The GROW method will increase the cloud's size by the  */
/* specified value and set the rain flags accordingly.    */
/* GROWメソッドは雲の大きさを指定の値だけ大きくし、結果に */
/* 応じてrain(降雨)フラグを設定する                     */
/**********************************************************/
::METHOD Grow
  Expose Name Size ItsRaining HeavyRain
  Use Arg Growth

  /* let the cloud grow */
  /* 雲を大きくする */
  Size = Size + Growth

  /* will it start raining, or even heavy rain? */
  /* 降雨が始まるか、雨は豪雨か? */
  If Size >= 70 Then
    ItsRaining = .True
  If Size >= 100 Then
    HeavyRain = .True

  /* print a short status message with the new cloud size */
  /* 雲の変更後の大きさを簡単に表示する */
  Say "Cloud '" || Name || "' has grown to" Size

/**********************************************************/
/* The SHRINK method will reduce the cloud's size by the  */
/* specified value and set the rain flags accordingly.    */
/* SHRINK(縮める)メソッドは指定の値だけ雲の大きさを小さ */
/* くする。結果に応じて降雨フラグを設定する               */
/**********************************************************/
::METHOD Shrink
  Expose Name Size ItsRaining HeavyRain
  Use Arg Reduction

  /* let the cloud shrink */
  /* 雲を小さくする */
  Size = Size - Reduction

  /* will it stop raining? */
  /* 降雨を終えるか? */
  If Size <= 60 Then
    HeavyRain = .False
  If Size <= 40 Then
    ItsRaining = .False

冷却 cool、加熱 heat メソッドは温度属性を直接操作せず、別のメソッドを通して変更を行う。その内一つのメソッドは温度の問い合わせ、もう一つは温度の設定を行う。こうすると、雨と雪との切り換えを一か所のコードでまとめてできる:

/**********************************************************/
/* The COOL method will reduce the cloud's temperature    */
/* by the specified value.                                */
/* COOLメソッドは雲の温度を指定の値だけ低下さす           */
/**********************************************************/
::METHOD Cool
  Expose Name
  Use Arg Reduction

  /* Set the new temperature and rain/snow flags. The     */
  /* current temperature is retrieved by invoking the     */
  /* TEMPERATURE method of the same object. The result    */
  /* of the subtraction is then used as an argument for   */
  /* the TEMPERATURE= method (special notation).          */
  /* 新しい温度と雨/雪フラグを設定する。現在の温度は     */
  /* TEMPERATUREメソッドで得る。新しい温度はTEMPERATURE=  */
  /* (特殊な名前)メソッドで設定する                     */
  Self‾Temperature = Self‾Temperature - Reduction

  /* print a short status message with the new cloud temp */
  Say "Cloud '" || Name || "' has cooled down to",
      Self‾Temperature "F"

/**********************************************************/
/* The HEAT method will increase the cloud's temperature  */
/* by the specified value.                                */
/**********************************************************/
::METHOD Heat
  Expose Name
  Use Arg Increase

  /* set the new temperature and rain/snow flags */
  Self‾Temperature = Self‾Temperature + Increase

  /* print a short status message with the new cloud temp */
  Say "Cloud '" || Name || "' has heated up to",
      Self‾Temperature "F"
温度を操作するメソッドはcloudクラスだけから呼ばれるはずなので、PRIVATE(自家用)メソッドとして宣言する。PRIVATEメソッドはクラスのメソッドから以外は見えない。:

/**********************************************************/
/* The private TEMPERATURE method will return the         */
/* cloud's current temperature                            */
/**********************************************************/
::METHOD Temperature PRIVATE
  Expose Temperature
  Return Temperature
温度を代入演算子 = で設定したいので、温度を設定するメソッドの名前に = を加える。こうすると、温度を設定するメソッドの呼び出しが読みやすくなる:

/**********************************************************/
/* The private TEMPERATURE= method will set the new       */
/* temperature and the rain/snow flag of the cloud.       */
/* 自家用メソッドの TEMPERATURE= は新しい温度を設定し     */
/* 雨/雪フラグを制御する                                 */
/**********************************************************/
::METHOD "Temperature=" PRIVATE
  Expose Temperature RainAction
  Use Arg Temperature

  /* set the rain/snow flag according to the temperature  */
  If Temperature > 32 Then
    RainAction = "raining"
  Else
    RainAction = "snowing"
cloudクラスの最後のメソッドは、雲が十分大きくなり雨を降らせたらいつでもそれを報告する。このメソッドは他のメソッドと並列動作する。起動後すぐに呼び側に制御を戻すが、メソッド自体は新しいスレッドで継続して実行される。ループの中でItsRainingに保護(guard)が設定される。この属性が真である限り、メソッドはメッセージを表示して雲の大きさを減少させる。減少量は雨の強さに応じて変わる:

/**********************************************************/
/* The private SHOWRAIN method will set a guard on        */
/* the ItsRaining flag. As soon as the cloud's state      */
/* changes to rain, this method will print messages that  */
/* the cloud is pouring rain. While raining the cloud     */
/* will shrink again (due to the loss of water).          */
/* 自家用SHOWRAINメソッドはItsRainingに保護を設定し、     */
/* 雲が雨を降らせはじめると、降雨メッセージを表示する。   */
/* 雨が降っている間、水を失うので雲は小さくなる           */
/**********************************************************/
::METHOD ShowRain PRIVATE
  Expose Name Size ItsRaining HeavyRain RainAction
  Reply /* return immediately to caller */

  /* this loop will run as long as the cloud exists       */
  /* 雲が消滅するまで繰り返す */
  Do ForEver
    /* wait for the cloud to reach the raining state      */
    /* 雲が雨を降らせるまで待つ */
    Guard Off When ItsRaining

    /* print raining message depending on the strength    */
    /* of the rain and reduce the size of the cloud       */
    /* 強さに応じ、降雨メッセージを表示し雲を小さくする   */
    If HeavyRain Then
      Do
        Say "Cloud '" || Name || "' is" RainAction,
            "heavily (size =" Size || ")."
        Self‾Shrink(6)
      End
    Else
      Do
        Say "Cloud '" || Name || "' is" RainAction,
            "(size =" Size || ")."
        Self‾Shrink(3)
      End

    /* rain always takes some time */
    /* 雨は降り出したら直ぐには止まない */
    Call SysSleep 4
  End
これでcloudクラスの全ての定義が終わった。cloudオブジェクトをクラスから作るために、プログラムの先頭に多少文を追加してもいい。でもこれでは並列動作の感じがわからない。インタラクティブなプログラムにしたい。REXXTRYは、Object REXXをインタラクティブにいじるための最適のプラットフォームである。元はREXXの文を試してみるためのインタラクティブなプログラムであるが、雲のオブジェクトをインタラクティブに空に浮かべることにも利用できる。

REXXTRYとPMREXXとを組み合わせるとさらによい。コマンドラインと出力を表示する領域(スクロールする)が別々に表示される。雲のクラスを作るには、まずPMREXXからREXXTRYを起動する。起動後、cloudクラスをコマンドファイルから呼び出して宣言する。これでcloudクラスはシステム「既知」なクラスになり、オブジェクトの生成と操作ができるようになる。生成、操作はObject REXXプログラムの中で行うのと同様に、コマンドラインから行えばよい。

以下はREXXTRY + PMREXXで雲のクラスを走らせたサンプルである。コマンドラインに入力されたコマンドは強調表示されている:


  rexxtry.CMD lets you interactively try REXX statements.
    Each string is executed when you hit Enter.
      Enter 'call tell' for a description of the features.
  Go on - try a few...             Enter 'exit' to end.
call cloud
  ...................................... rexxtry.CMD on OS/2
a = .cloud‾new("A", 50, 50)
Cloud 'A' has grown to 50
  ...................................... rexxtry.CMD on OS/2
a‾grow(20)
Cloud 'A' has grown to 70
  ...................................... rexxtry.CMD on OS/2
Cloud 'A' is raining (size = 70).
Cloud 'A' is raining (size = 67).
a‾grow(20)
Cloud 'A' has grown to 84
  ...................................... rexxtry.CMD on OS/2
Cloud 'A' is raining (size = 84).
a‾grow(20)
Cloud 'A' has grown to 101
  ...................................... rexxtry.CMD on OS/2
Cloud 'A' is raining heavily (size = 101).
Cloud 'A' is raining heavily (size = 95).
Cloud 'A' is raining heavily (size = 89).
Cloud 'A' is raining heavily (size = 83).
Cloud 'A' is raining heavily (size = 77).
b = .cloud‾new("B", 70, 40)
Cloud 'B' has grown to 70
  ...................................... rexxtry.CMD on OS/2
Cloud 'B' is raining (size = 70).
Cloud 'A' is raining heavily (size = 71).
Cloud 'B' is raining (size = 67).
Cloud 'A' is raining heavily (size = 65).
b‾cool(5)
Cloud 'B' has cooled down to 35 F
  ...................................... rexxtry.CMD on OS/2
Cloud 'B' is raining (size = 64).
Cloud 'A' is raining (size = 59).
Cloud 'B' is raining (size = 61).
Cloud 'A' is raining (size = 56).
b‾cool(5)
Cloud 'B' has cooled down to 30 F
  ...................................... rexxtry.CMD on OS/2
Cloud 'B' is snowing (size = 58).
Cloud 'A' is raining (size = 53).
Cloud 'B' is snowing (size = 55).
Cloud 'A' is raining (size = 50).
Cloud 'B' is snowing (size = 52).
Cloud 'A' is raining (size = 47).
Cloud 'B' is snowing (size = 49).
Cloud 'A' is raining (size = 44).
b‾heat(5)
Cloud 'B' has heated up to 35 F
  ...................................... rexxtry.CMD on OS/2
Cloud 'B' is raining (size = 46).
Cloud 'A' is raining (size = 41).
Cloud 'B' is raining (size = 43).

[ Previous page | Tutorial Index | ]