2010年11月10日水曜日

非同期呼び出しについてのメモ

非同期呼び出しが絡んだ設計方法についてのメモです。

※以下、実装がマルチスレッドなのかシングルスレッドなのかは無視して考えましょう。

いい感じの本

Enterprise Integration Patterns とかいい感じっす。ECMA Script 系で必要とされるような非同期処理を扱う雰囲気の本ではなくて JMS や MQ 系のメッセージイングサーバを意識した本なのですが、最初の方の章が非同期処理に関する説明がいい感じで載っています。

おいらも読みなおしたいんだけど、日本に置いてきたので今は読めません(´・ω・`)

同期呼び出しのみの場合
スレッド1:処理A -> 処理B -> 処理C のように実行される。

ある処理が非同期処理に依存する場合

すべての処理が非同期だが、すべての処理が依存関係を持つ場合。
スレッド1:処理Aに処理Bをコールバック登録してフォーク 
スレッド2:     処理A実行 -> 処理Bに処理Cをコールバック登録してフォーク
スレッド3:            処理B実行 -> 処理Cにフォーク
スレッド4:                   処理C実行
この手の処理が、かなり面倒。そもそも概念的に非同期処理でないものを実装上強引に非同期処理にしているだけであり、同時並行処理のメリットが全く無い(シングルスレッド環境などの制約条件下でしかたなく対応するケースがほとんどだと思われ)。しかし、依存する処理をコールバックに変換するだけなので、同期呼び出しの場合からの機械的な変換は可能。この手の設計になる場合、同期処理で擬似コードを書いてから、その後機械的に非同期処理に変換したほうがいいかも。

非同期呼び出しにより処理がフォークする場合

各処理に依存関係がない場合は以下のように4つのスレッドが別々に動作する。
スレッド1:処理Aフォーク -> 処理Bフォーク -> 処理Cフォーク 
スレッド2:              -> 処理A
スレッド3:                               -> 処理B
スレッド4:                                               → 処理C
スレッド1の動作は一瞬にして行われるので、処理A,B,Cはほぼ同時に開始する。このような非同期処理は、人間から見てもそこそこ直感的。多くの場合シーケンシャルに動作させた場合よりも高い性能が得られる。

非同期呼び出し処理がジョインする場合

処理A,B,Cのすべてが完了したあとに次の処理が行われる場合の例
スレッド1:処理Aフォーク -> 処理Bフォーク -> 処理Cフォーク 
スレッド2:              -> 処理A -> 合流条件確認 -> (失敗)
スレッド3:                               -> 処理B                         -> 合流条件確認 -> (成功) -> 合流後の処理
スレッド4:                                                -> 処理C -> 合流条件確認 -> (失敗)
非同期処理のパフォーマンスを享受しつつ、処理の同期もおこなってしまうというおいしいところ取りですね。ジョインする条件の確認や、その条件を構成する情報の登録などをする必要があるのでコーディングレベルでは少しめんどくさいのですが、事前に設計をきちんとやっておけば問題ないでしょう。

設計方針考察

まずは、fork と join の発生する処理は避けて実装する。非同期処理を利用するとしても陸上のリレーのようにコールバックを用いて処理を継続させる方法であれば、join 条件のチェックが必要無いので設計がシンプルになる。この方法で、一通り実装して、実装した機能が仕様を満たしていることを確認する。

以下書きかけ。
  1. 設計対象の1つの処理を決定する。
  2. 処理内にて順次処理とフォークする処理とジョイン後の処理を、最外殻のレベルで分類し、各々の処理の塊をグループとする。
  3. 上記グループのうち、最外殻のジョイン処理とそれにジョインされる処理を1つのグループとして扱う。
  4. 複数のグループが残った場合、上記の各グループをメソッド化し、それそれを順次実行する。(各々が依存関係を持たないため並行動作が可能)
  5. 単一の順次処理の場合はそのまま記述すればよい。非同期処理は必要ない。
  6. 単一のジョインされるグループが残った場合、ジョイン実行条件のための情報(ジョイン実行条件判断クロージャから見えるスコープのフラグなど)を用意し、ジョイン実行条件を判断するクロージャを用意し、ジョイン実行条件のための情報の変更を通知するためのクロージャを用意し、ジョイン後の処理のクロージャを用意し、残りのグループを各メソッドとして作成して引数にジョイン実行条件判断用のクロージャと情報通知用クロージャとジョイン後の処理のクロージャを渡すようにする。
以降、上記の1からをネストして行う。
この説明じゃおいら自身以外にはわからんよねw まぁ、個人的なメモなので、、、。

まとめ

同一スレッドでの順次処理、フォーク、ジョインの3種類を適切に考えて設計すればよいということですね。

このような概念を用いた設計はプログラミング言語で記述することは直感的ではないと思うので(少なくともおいらには)、コーディングに入る前にアクティビティ図のような形で設計してみたほうがよいと思います。

2010年11月4日木曜日

Flash IDE 上でのアルファを変えるだけの簡単なボタンの作成

今回は、Flashの勘所を友人に教わりつつ、簡単なボタンのコンポーネントを作成してみました。

概要
任意のSpriteを継承したオブジェクトに対して、マウスのロールオーバー時に alpha の値を変更する振る舞いを付加するコンポーネントおよびライブラリです。

仕様
AlphaTransitiveButtonクラス
  • 概要
    • ロールオーバー時に alpha が変化する Sprite です。
    • ボタンモードはオンになります。
  • メリット
    • Flash IDE 上のシンボルからリンクするだけで、シンボルに対してロールオーバー時に alpha が 0.5 に変化する振る舞いを与えることができます。
    • 自前の ActionScript を作成する必要がありません。
  • 備考
    以下の場合、AlphaTransitiveButton クラスを使用せずに ButtonUtils の addXxxBehavior() 系のメソッドを利用の検討を推奨します。
    • 既に継承を使用しているために継承が使えない場合。
    • Alpha を独自に設定したい場合。
    • 継承を使いたくない場合。(例:10種類の振る舞いを追加するために10回継承するということを避けたい場合)
ButtonUtilsクラス
  • 概要
    • 指定された Sprite クラス(もしくは Sprite を継承したクラス)にロールオーバー時に alpha が変化する振る舞いを付加します。
    • ボタンモードはオンになります。
  • 備考
    • Flash IDE 上のシンボルに対して本メソッドのデフォルトの振る舞いを追加する場合は AlphaTransitiveButton クラスの利用も検討してみてください。
    サンプル

    • 上のボタンは AlphaTransitiveButton クラスにリンクしています。
    • 下のボタンは、ボタンのシンボルの1フレーム目で ButtonUtils#addAlphaTransitiveButtonBehavior(target, rollOverAlpha) を呼び出し、rollOverAlpha を0.8に設定しています。
    ソース

    AlphaTransitiveButtonクラス
    package {
        
        import flash.display.Sprite;
        import flash.events.MouseEvent;
        
        /**
         * ロールオーバー時に alpha が変化する Sprite です。
         * ボタンモードはオンになります。
         * 
         * メリット
         *  ・ Flash IDE 上のシンボルからリンクするだけで、シンボルに対してロールオーバー時に alpha が 0.5 に変化する振る舞いを与えることができます。
         *  ・ 自前の ActionScript を作成する必要がありません。
         * 
         * 備考
         *  ・ 以下の場合、AlphaTransitiveButton クラスを使用せずに ButtonUtils の addXxxBehavior() 系のメソッドを利用の検討を推奨します。
         *    ・ 既に継承を使用しているために継承が使えない場合。
         *    ・ Alpha を独自に設定したい場合。
         *    ・ 継承を使いたくない場合。(例:10種類の振る舞いを追加するために10回継承するということを避けたい場合)
         * 
         * @see ButtonUtils#addAlphaTransitiveButtonBehavior(Sprite, Number)
         */
        public class AlphaTransitiveButton extends Sprite {
            
            public function AlphaTransitiveButton() {
                ButtonUtils.addAlphaTransitiveButtonBehavior(this);
            }
        }
    }
    

    ButtonUtilsクラス
    package {
        
        import flash.display.Sprite;
        import flash.events.MouseEvent;
        
        /**
         * ボタン関連のユーティリティクラスです。
         */
        public class ButtonUtils extends Sprite {
            
            /**
             * 指定された Sprite クラス(もしくは Sprite を継承したクラス)にロールオーバー時に alpha が変化する振る舞いを付加します。
             * ボタンモードはオンになります。
             * Flash IDE 上のシンボルに対して本メソッドのデフォルトの振る舞いを追加する場合は AlphaTransitiveButton クラスの利用も検討してみてください。
             * 
             * 注: target が Dynamic Text の TextArea の場合など、特定の条件下でマウスオーバー時にマウスカーソルの形状が変化しない場合があります。(flash側の問題)
             * 
             * @param target 対象となる Sprite
             * @param rollOverAlpha ロールオーバー時の alpha の値
             * @see AlphaTransitiveButton
             */
            public static function addAlphaTransitiveButtonBehavior(target:Sprite, rollOverAlpha:Number = 0.5) {
                target.buttonMode = true;
                target.addEventListener(MouseEvent.ROLL_OVER, function(e:MouseEvent):void {
                    e.currentTarget.alpha = rollOverAlpha;
                });
                target.addEventListener(MouseEvent.ROLL_OUT, function(e:MouseEvent):void {
                    e.currentTarget.alpha = 1;
                });
            }
        }
    }
    
    アーカイブ

    2010年11月1日月曜日

    Flash IDE 上でのMVCについて考えてみた

    Flash IDE 上でのMVCについて考えてみた(その2) が最新です。

    近々、Flash IDE で開発を行うことになりました。

    開発に入る前の実験として、ステージ上に色々とコンポーネントを配置して、Documentクラスに ActionScript のコードを記述して、なんとなく動くものを作っていたというのがこれまでの話。しかし、これでは保守性に難があるなぁと思う今日この頃。

    保守性を向上させようと考えた場合に、すぐに思い浮かぶのはコンポーネント化。コンポーネント内部はシンプルなMVCがよさそう。

    ということで、実験してみました。

    方式
    • Flash IDE 上で作成したシンボルから as ファイルにリンクを張る方式。
    • 名前空間は Flash IDE 上の LIBRARY 内にフォルダを作成して対応する。

    今回作成するサンプル
    • TextArea に最初 0 が表示され、マウスでクリックするたびに値が 1 増えるアプリ。


    シンボル
    • LIBRARY 内のフォルダ名
      • com.objectfanatics.samplecomponent
    • シンボル名
      • View
    • リンク先のクラス
      • com.objectfanatics.samplecomponent.view.View

    クラス構成
    • com.objectfanatics.samplecomponent.model パッケージ
      • com.objectfanatics.samplecomponent.model.Model
        • コンポーネントのモデルのインタフェース。
        • モデルは可能な限り実装を意識しないで設計したいため、あえてインタフェースを作成。
      • com.objectfanatics.samplecomponent.model.ModelImpl
        • コンポーネントのモデルの実装。
      • com.objectfanatics.samplecomponent.model.ModelListener
        • Model の変更内容を監視するためのリスナーインタフェース
    • com.objectfanatics.samplecomponent.view パッケージ
      • com.objectfanatics.samplecomponent.view.View
        • Flash IDE 上で作成したシンボルからリンクされるクラス。
        • View として存在すると同時に、コンポーネント全体を構築する役割も持つ。
      • com.objectfanatics.samplecomponent.view.ModelListenerImpl
        • Model の変更を監視し、Model の変更内容に応じて View を更新するクラス。
        • ModelListenerインタフェースの実装クラス。
    • com.objectfanatics.samplecomponent.controller パッケージ
      • com.objectfanatics.samplecomponent.controller.Controller
        • View の内部要素に対してリスナーを登録し、イベントを監視する。
        • View からのイベントを処理し、必要に応じて Model を更新する。 

    クラスのソース
    package com.objectfanatics.samplecomponent.model {
     
     public interface Model {
      
      /**
       * ModelListener をセットします。
       * @param modelListener ModelListener
       */
      function setModelListener(modelListener:ModelListener):void;
      
      /**
       * 値を返します。
       * @return 値
       */
      function getNumber():uint;
      
      /**
       * 値を1増やします。
       */
      function increment():void;
     }
    }
    

    package com.objectfanatics.samplecomponent.model {
     
     public class ModelImpl implements Model {
      
      private var modelListener:ModelListener;
      
      /**
       * 保持される値
       */
      private var number:uint = 0;
      
      /**
       * Model#getNumber():uint の実装
       */
      public function getNumber():uint {
       return number;
      }
      
      /**
       * Model#setModelListener(modelListener:ModelListener):void の実装
       */
      public function setModelListener(modelListener:ModelListener):void {
       this.modelListener = modelListener;
      }
      
      /**
       * Model#increment():void の実装
       */
      public function increment():void {
       this.modelListener.numberChanged(++number);
      }
     }
    }
    

    package com.objectfanatics.samplecomponent.model {
     
     /**
      * Model の変更内容を監視するためのリスナー
      */
     public interface ModelListener {
      
      /**
       * 値が変更された場合に呼び出されます。
       * @param number 現在の値
       */
      function numberChanged(number:uint);
     }
    }
    

    package com.objectfanatics.samplecomponent.view {
     
     import flash.display.Sprite;
     
     import com.objectfanatics.samplecomponent.model.Model;
     import com.objectfanatics.samplecomponent.model.ModelImpl;
     import com.objectfanatics.samplecomponent.model.ModelListener;
     import com.objectfanatics.samplecomponent.controller.Controller;
     
     /**
      * FlashIDE 上の LIBRARY にて、フォルダ名が com.objectfanatics.samplecomponent、名前が View のシンボルに対応するクラス。
      * View という名前ですが、FlashIDE上で作成したシンボルからのリンクとなっているため、コンポーネント全体の初期化も行っています。
      * 純粋な View としての処理は、 Model には依存しますが Controller には依存しません。
      */
     public class View extends Sprite {
      
      private const model:Model = new ModelImpl();
      
      public function View():void {
       initView();
       model.setModelListener(new ModelListenerImpl(this));
       new Controller(this, model);
      }
      
      private function initView():void {
       this.numberText.text = "" + model.getNumber();
      }
     }
    }
    

    package com.objectfanatics.samplecomponent.view {
    
     import com.objectfanatics.samplecomponent.model.ModelListener;
      
     /**
      * Model の変更内容を監視し View に反映させるための ModelListener の実装クラス。
      */
     public class ModelListenerImpl implements ModelListener {
      
      /**
       * 変更対象の View
       */
      private var view:View;
      
      /**
       * コンストラクタ
       * @param view 変更対象の View
       */
      public function ModelListenerImpl(view:View):void {
       this.view = view;
      }
      
      /**
       * Model の値が変更された時に呼び出され、View 上の表示を変更します。
       * @param currentNumber 現在のの Model の値
       */
      public function numberChanged(currentNumber:uint) {
       view.numberText.text = "" + currentNumber;
      }
     }
    }
    

    package com.objectfanatics.samplecomponent.controller {
     
     import flash.events.MouseEvent;
     
     import com.objectfanatics.samplecomponent.view.View;
     import com.objectfanatics.samplecomponent.model.Model;
     
     public class Controller { 
      
      private var model:Model;
      
      private var view:View;
      
      public function Controller(view:View, model:Model):void {
       
       // Model と View の格納
       this.model = model;
       this.view = view;
       
       // View のクリックの検出設定
       view.addEventListener(MouseEvent.CLICK, function():void{model.increment()});
      }
     }
    }
    

    今回の所感

    単純な仕様のコンポーネントであれば、この方法でも十分な保守性が得られるのではないかと思いました。しかし、複雑になるとどうなるか全く見当も付きません。実際に複雑なケースに適用してみて実際に問題が生じたときに、その問題をシンプルに表現できる例題を作成して考察してみようと思います。

    全体的な仕組みとして再利用が効きそうなポイントが多々あるのですが、ことごとくうまくいきませんでした。たとえば、Viewクラスの内部は Template Method を適用すればコード量抑えられるしロジックを完全に隠蔽できるので保守性が上がりそうなものです。しかし、abstract class が使えないために Template Method のメリットがかなり小さくなってしまいます。通常のクラスで Template Method を試してもみたのですが、Generics が使えないために手動での強引な型変換が必要となり、ソースがかなり長く見辛くなってしまいました。

    まだ as3 を触り始めてまもないので、当面は粛々と実験していきたいと思います。

    アーカイブ

    2010年7月30日金曜日

    カナダネタ:ホテル予約編

    突然ですが、業務として8月から半年ほどバンクーバー(カナダ)に行くことになりました。

    ということで以下、ホテルの予約メモ。
    なにげに結構大変でしたw

    まず、安い宿がほとんどありません。数年前シリコンバレーにいた時は、ダウンタウンの交通の便がよいところでさえシングルルーム(風呂、トイレ、朝食、電話、高速インターネット回線付き)で$1,050/month、ダブルでも$1,200/month程度で借りられました。飛び込みでも普通のシングルルームで45$あれば借りることができました。月極のフラットを1室借りる場合は、$1,000/month前後でした(電話回線の契約とか自分でする必要がありますが)。しかし、バンクーバーではそうはいかないようです。


    ホテルを物色してみた

    Shaughnessy Village Vancouver

    かなり安い宿です。8月は最高値なのですが、それでも$1045/momth。安いです。よさそうなので、メールでいくつか質問してみました。すると、3ヶ月で$915/month, 6ヶ月で$885/monthとのこと。さらに安い! しかし、途中でのキャンセルについては支払った金額が全く払い戻されないということでした。個人的に、過去にこのような厳しい払い戻しルールの長期滞在用ホテルは経験したことも聞いたこともなく、メールが英文メールとしてもあまりにもぶっきらぼうであり、また、いくつかの質問をさらっと無視されてしまったので、念のため、評判をググッてみました。う~む。賛否両論ですが、事前に長期予約をするにはリスクが大きそうな感じですね。


    YWCA of Vancouver

    口コミの評価がかなり高いです。Single (1 single bed) with semi- private bath*, TV の weekly rate が $74/night ということで、かなりリーズナブル。semi- private bath* は、2部屋で共有とのこと。"We also offer residence rate if you stay for a minimum of 30 days"とのことで、もっと長く止まるなら、もう少し安くなりそうです。


    The Kingston Hotel

    シャワールームが共有で、シングルルームが $75 - $125 plus tax とのこと。8月はハイシーズンなので、125$/nightになりそうですね。monthlyのrateも乗っていないので、今回は見送り。


    結局・・・

    結局、とりあえずYWCAを1ヶ月だけおさえることにして、その間に家具付きのフラットを借りる方向で進めてみることにしました。その際、もし途中キャンセルが可能なら6ヶ月間の予約を入れるという選択肢も残しておきます。

    ということで、availability と monthly rate の確認と、6ヶ月の予約を入れるが途中キャンセルする可能性があるという状況でよい案がないかなという質問をメールで確認したところ、非常に丁寧な回答メールを頂きました。以下要約。
    • 30日以上連続して宿泊する場合は、月単位のResidence形式を選択することが可能。その際、ホテルスタッフからの承認が必要になる(Residenceの情報)。しかし、8月はハイシーズンなので daily のレートのみ。
    • 長期滞在で部屋を出る日付が未定の場合は、ひとまず長期の予約をしておいて、部屋を出る1ヶ月前に話せばよい。
    • 全館禁煙。
    • 無線LANはロビーと各部屋で利用可能。価格は $6.00/day, $22.00/week, or $33.00/month。
    weekly rate も residence rate も適用できないのは残念ですが、とりあえず8末まではここを押さえようとしたところ、シングルが空いてませんでした(´・ω・`)

    となると、ダブルになるので1日 $98.00 です。う~む、高いな。シャワー共有でこの値段は割に合わないなぁ、、、。しかし、今後ここに residence rate で宿泊する可能性も考えると、事前調査という意味ではアリか、、、、。このシーズンはどこも満室だし、中級ホテルでも$200/day弱するし、、、。

    ということで、到着日の8日から、某お祭りが終わって落ち着く頃ということで18日まで10夜分だけ予約を取ることにしました。(そして、PDF付きの確認メールがスパムフィルタにかかるのはお約束w)

    2010年7月28日水曜日

    就業規則の届出をしていない場合の旅費規程について

    弊社は現在常時10人以上の労働者を使用していないため、労働基準監督署に就業規則を届けていません。そのため、旅費規程などについても届出をしていません。その場合、旅費規程により経費として扱われることが妥当な場合でも、所得税が課税される可能性がありうるのではという疑問があります。

    ということで、労働基準監督署に聞いてみました。

    労働基準監督署曰く
    • 旅費規定等を単独で届け出ることはできず、就業規則を含めて提出する必要がある。
    • 税金については関知しない。
    • 今回の件では特に届けでの必要はない。
    とのこと。今度は税務署に聞いてみました。

    税務署曰く
    • 労働基準監督署に届けるかどうかは関係ない。
    • 調査が必要な場合などに、該当する書類を見せられるようにしておけばよい。
    • 書類の内容の妥当性は、地域性その他を含めた全体的な視点で判断される。
    とのことでした。

    妥当な規則を事前に用意していれば、特に問題なさそうです。

    2010年6月7日月曜日

    Utils.as

    package {
        import flash.filesystem.File;
        import flash.filesystem.FileMode;
        import flash.filesystem.FileStream;
        
        /**
         * とりあえず、静的な便利メソッドを入れ込んでおくクラス。
         * 
         * TODO: Air 以外の開発をする際に、Air 専用とそれ以外を分離しましょう。
         * 
         * 方針
         *         ・ActionScriptはオーバーロードができないので、メソッド名に引数情報もいれる。
         *         ・見かけの簡潔さを求めず、分かりやすさを求める。初めて見る人でもシグニチャだけで機能を確実に理解できることを目指す。
         *         ・管理しきれなくなって『具体的に困る』ことになったら別ライブラリへの分割を考える。
         */
        public class Utils {
            
            /**
             * 指定された XML ファイルを読み込み XML オブジェクトを返します。
             */
            public static function readXmlFromFile(xmlFile:File):XML {
                return new XML(readUTFBytesFromFile(xmlFile));
            }
            
            /**
             * 指定されたファイルを読み込み UTFBytes を返します。
             */
            public static function readUTFBytesFromFile(utfFile:File):String {
                var fileStream:FileStream = new FileStream();
                fileStream.open(utfFile, FileMode.READ);
                var utfBytes:String = fileStream.readUTFBytes(utfFile.size);
                fileStream.close();
                return utfBytes;
            }
            
            /**
             * 指定されたファイルに対して指定された XML を書き込みます。
             */
            public static function writeXmlToFile(xml:XML, file:File):void {
                writeUTFBytesToFile(xml.toXMLString(), file);
            }
            
            /**
             * 指定されたファイルに対して UTFBytes を書き込みます。
             */
            public static function writeUTFBytesToFile(utfBytes:String, file:File):void {
                var fileStream:FileStream = new FileStream();
                fileStream.open(file, FileMode.WRITE);
                fileStream.writeUTFBytes(utfBytes);
                fileStream.close();
            }
            
            /**
             * 指定されたファイルをファイルシステム中に作成します。既に指定されたファイルが存在する場合には何もしません。
             */
            public static function createFile(file:File):void {
                if (!file.exists) {
                    var fileStream:FileStream = new FileStream();
                    fileStream.open(file, FileMode.WRITE);
                    fileStream.close();
                }
            }
        }
    }
    

    2010年6月2日水曜日

    FlashのUI系コンポーネント調査

    FlashのUI系のコンポーネントについて全く知識がないので、少し調査してみました。

    クラス階層

    Object
    ・言うまでもなく、あらゆるクラスのベースとなるクラス。特にUIであるかどうかとは無関係。
    ・パッケージはトップレベル。

    flash.events.EventDispatcher
    flash.events.IEventDispatcher の実装クラス。
    ・イベントを扱うための汎用的な機能を持つクラス。リスナーの追加削除とかイベントの送信とか。
    ・特にUIであるかどうかとは無関係。

    flash.display.DisplayObject
    ・display list に配置されるすべてのオブジェクトのベースクラス。
    ・x,y,zとかalphaとかwidthとかvisibleとかマウス位置とか、表示されるものとしての基本機能を持っている。

    flash.display.InteractiveObject
    ・表示されるオブジェクトでマウスやキーボードやその他の入力デバイスを扱うものすべての抽象クラス。
    ・このクラスはnewできないし、上記までのクラスもUIを作成するうえでプログラマが明示的に new することはなさそうです。

    flash.display.DisplayObjectContainer
    ・display object の入れ物クラス。
    ・z 軸上に複数の display object を child として配置できる。
    ・このサブクラスには Loader, Sprite, Stage, TextLine があります。

    flash.display.Loader
    ・java の ClassLoader のようなものを想像していると DisplayObjectContainer のサブクラスということに違和感を感じるが、実際は swf ファイルおよび画像ファイルをロードして表示するものなので、表示オブジェクトのローダーと言える。
    ・flex 用のサブクラスとして mx.core.FlexLoader があり、toString() メソッドが DisplayObjects の階層を表すようになっている。

    flash.text.engine.TextLine
    ・display text 上に文字列を表示するためのオブジェクト。
    ・final クラスなので継承できないし、ユーザが直接 new することもできない。
    ・flash.text.engine 系のパッケージと関わらない限りは必要なさそう。

    flash.display.Stage
    ・ブラウザ内なら flash の表示領域が Stage で、Airなら各 NativeWindow が Stage を持つ。

    flash.display.Sprite
    ・UI 系の一般的なベースクラスで、MovieClip からtimelineを抜いたようなもの。