MOSA Multi-OS Software Artists

MOSAはソフトウェア開発者を支援します

プログラマーに興味がある方なら誰でも入会いただけます。
MOSA Multi-OS Software Artists
===SINCE 1995===

  • iPhone/iPod touch アプリ紹介
  • MOSA掲示板
  • 活動履歴
  • About MOSA(English)

MOSADenバックナンバー 2004年12月発行分

  • MOSA Developer News[MOSADeN=モサ伝]第142号

    2004-12-28

    目次

    • SqueakではじめるSmalltalk入門  第24回  鷲見 正人
    • 小池邦人の「Carbon API 徒然草」
    • 「Behind the WebObjects」    第34回  田畑 英和

    SqueakではじめるSmalltalk入門   第24回  鷲見 正人

     本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。今回は、「再定義していないメソッドが、なぜ多態性を発揮できるのか」についてです。

    簡単のため、2つある出納用メソッドのうち、#deposit:のみに注目します。次のようなスクリプトをdo it (cmd-D)した(あるいは、stockの中身を観察するためにinspect it (cmd-I)した)と想定します。

    | stock |
    stock _ StockAccount new.
    stock deposit: 300.
    ^ stock

     ここで、stockに束縛されたa StockAccountは、「deposit: 300」というメッセージを受け、自らが属するクラスStockAccountで、#deposit:というメソッドを探します。しかし、我々はそれを再定義していないので、該当するメソッドを見つけることは叶いません。しかたがないのでスーパークラスであるBankAccountにおいて改めて#deposit:を探し、見つけてそれを起動します。【註】

    BankAccount >> deposit: aNumber
      self balance: self balance + aNumber

     すでにご存じのとおり、もともとこのメソッドは、selfにa BankAccountが束縛されることを念頭に記述されたものです。その振る舞いは、self balanceの返値とaNumberの和をパラメータにして、「balance: …」というメッセージをselfに送る…というものです。selfがa BankAccountなら、「balance」、「balance: …」というメッセージはそれぞれ対応するBankAccount >>#balance、BankAccount >> #balance:を起動して話はおしまいです。

    BankAccount >> balance
      ^ balance ifNil: [balance _ 0]
    
    BankAccount >> balance: aNumber
      balance _ aNumber
    


     しかし、今selfには、このメソッドを起動するきっかけを作ったメッセージ式におけるレシーバ、つまり、a StockAccountが束縛されています。したがって、このコンテキスト(文脈、あるいは、メソッド実行時のインタープリタの内部状態)において、「balance」および「balance: …」というメッセージを受けたself、つまりa StockAccountは、自らの属するクラスStockAccountにて#balance、#balance:メソッドを探し、見つけることができれば(当然、我々はそうしたメソッドをStockAccountに再定義済みなので必ず見つかるわけですが)それらを起動します。

    StockAccount >> balance
      ^ self pricePerShare * self numShares
    
    StockAccount >> balance: aNumber
      self numShares: aNumber asFloat / self pricePerShare

     この2つのメソッドは、インスタンス変数balanceへのアクセスを行なうBankAccount >> #balance、#balance:と、同名で、同種のメッセージで起動される点では一緒なのですが、その内容、つまり振る舞いはまるで異なります。したがって結果的に、これらのメソッドを起動するBankAccount >> #deposit:や#withdraw:も、その振る舞いを変える、つまりレシーバに合わせて相応しい多態性を発揮できる、というわけです。少々込み入った話になってしまいましたが、以上が、再定義なしに出納用メソッドがうまく機能する“からくり”です。

    もちろん、スーパークラスのメソッドに、このような振る舞いをさせるには、設計段階からの準備が必要です。たとえば、当初、出納用メソッドを定義する際に候補にあった、インスタンス変数balanceへの直接参照で記述してしまっていたならば、単純にそれらをサブクラスで再定義するしかStockAccountを実現する方法はなくなります。

    BankAccount >> deposit: aNumber
      balance _ balance + aNumber
    
    BankAccount >> withdraw: aNumber
      balance _ balance - aNumber max: 0

        ↓

    StockAccount >> deposit: aNumber
      numShares _ numShares + (aNumber asFloat / pricePerShare)
    
    StockAccount >> withdraw: aNumber
      numShares _ numShares - (aNumber asFloat / pricePerShare) max: 0

     すでに扱った初期化の問題を無視すれば、確かにこれでうまくStockAccountは機能します。もっともこの場合、結果として、スーパークラスBankAccountのメソッドをすべてオーバーライドした状態になるので、ここで継承を使う“うま味”はまったくなくなってしまうのですが…。

    註:メソッドのメッセージパターンには、本来不要な「クラス名 >> 」という表現を追記して、そのメソッドがどのクラスに帰属するのかを明示的にすることがあります。もしブラウザなどにコピー&ペーストしてそのまま使用するときは、「クラス名 >> 」の部分は選択せずに、それを省いた残りをコピーするようにしてください。

    バックナンバー:
    http://squab.no-ip.com:8080/mosaren/

    小池邦人の「Carbon API 徒然草」(2004/12/24)

    Navigation Service APIの活用(その1)

    今回は、メインウィンドウを閉じるときに実行されるcloseCatalogWindow()の内部で使われている自作ルーチンを調べてみます。加えて、ファイルの読み込み時や保存時に活用するNavigation Serviceについても解説いたします。まずは、ウィンドウを閉じる処理を担当しているcloseCatalogWindow()をもう一度見てみましょう。

    short closeCatalogWindow( WindowRef window,short quit )
    {
        short    chk,ret=0;
    
        if( IsWindowModified( window ) ) // ドキュメントに何らかの変更があったか?
        {
            chk=navMySaveAlert( window,quit ); // 保存を行うか尋ねるアラートを表示
            if( chk==1 )
                ret=saveCatalogFile( window ); // 「保存」ボタン(ドキュメント保存)
            else if( chk==2 )                  // 「キャンセル」ボタン(処理中止)
                ret=1;
        }                                      // 「保存しない」ボタンが押された時
        if( ret==0 )                           // もしくは正常に保処理が終了した時
            disposeCatalogWindow( window );    // ウィンドウを閉じてメモリの解放
        return( ret );
    }
    


    このルーチンは、ユーザがファイルメニューから「閉じる」を選択するか、ウィンドウタイトル左端のクローズボックスをクリックした時に実行されます。また、アプリケーションを終了させる時点でオープンしているウィンドウがあれば、終了の処理を担当しているquitApplication()から呼ばれます(引数quitに1が代入される)。ドキュメントに何らかの編集が施されているかどうかをWindow Manager APIのIsWindowModified()で調べ、もしそうであれば、適切な処理を追加実行しています。その最初の仕事が「まだ保存されていませんがどうしますか?」という内容のアラートを表示することです。このアラート表示を行っているのが、以下のnavMySaveAlert()ルーチンです。

    short navMySaveAlert( WindowRef window,short quit )
    {
        NavAskSaveChangesResult       reply;    // アラートのボタン番号が返る
        short                         ret=0;
        NavDialogOptions              opt;      // オプション用構造体
        NavAskSaveChangesAction       act;      // タイトルの種類を選ぶ
    
        SysBeep( 1 );                           // ビープ音を一度鳴らす
        myCursor( 0 );                          // カーソルの形状を矢印に
        NavGetDefaultDialogOptions( &opt );     // アラートのオプションを初期化
        GetWTitle( window,opt.savedFileName );  // ドキュメント名を設定する
        GetIndString( opt.clientName,128,1 );   // アプリケーション名を設定する
        if( quit )                              // アプリ終了時に呼ばれた...
            act=kNavSaveChangesQuittingApplication;
        else                                    // ウィンドウを閉じる時に呼ばれた...
            act=kNavSaveChangesClosingDocument;
        if( ! NavAskSaveChanges( &opt,act,&reply,NULL,NULL ) ) // アラート表示実行
            ret=reply;
        return( ret );  // ボタン番号を返す(1.保存 2.キャンセル 3.保存しない)
    }
    


    Mac OS XのCarbon Frameworkには、ファイルの「読み込み」や「保存」の実現を容易にするために、「Navigation Service」というAPI群が用意されています。例えば、あるアプリケーションでファイルをオープンしようとすると、ファイル一覧を表示したダイアログが表示されますが、それを実行しているのがNavigation ServiceのAPIなのです。そうしたAPIのうち、navMySaveAlert()でファイル保存を促すためのアラートを表示しているのは、NavAskSaveChanges() APIです。NavAskSaveChanges()と同種のアラート用APIとしては、NavCustomAskSaveChanges()やNavAskDiscardChanges()などがあります。後者はファイルメニューの「復帰…」が選択された時に、「変更内容を破棄する」というタイトルのアラートを表示します。このAPIを使えば、破棄を許すかどうかをOKかキャンセルボタンでユーザに選択させることができるわけです。

    Navigation Serviceで表示できるダイアログやアラートは、NavDialogOptions構造体の内容を操作することにより、色々なオプション機能を追加することが可能です。ここでは、まずNavGetDefaultDialogOptions()を実行し、NavDialogOptions構造体の内容を初期化しています。その後、ドキュメント名をopt.savedFileNameに代入することで、「書類”…”に加えられた変更を保存しますか?」と表示される注意文章の”…”の部分に、ドキュメント名を挿入することが可能です。また、アラートのタイトルは2種類から選択でき、引数で渡すNavAskSaveChangesActionをkNavSaveChangesClosingDocumentにすれば、タイトルは「閉じる前に変更内容を保存する」となり、kNavSaveChangesQuittingApplicationにすれば「終了する前に変更内容を保存する」となります(日本語の場合)。

    NavAskSaveChanges()は、ユーザがクリックしたボタンの番号をNavAskSaveChangesResultに返してきます。その値は以下のように定義されています。

    typedef UInt32 NavAskSaveChangesResult;
    enum {
            kNavAskSaveChangesSave        =1, // 「保存」ボタン
            kNavAskSaveChangesCancel      =2, // 「キャンセル」ボタン
            kNavAskSaveChangesDontSave    =3  // 「保存しない」ボタン
         };
    


    closeCatalogWindow()では、このボタン番号を参照することで、「保存」「キャンセル」「保存しない」に対応した処理に分岐させます。そのうち「保存」ボタンが押された場合には、以下のsaveCatalogFile()ルーチンが呼ばれています。この中でファイル保存用ダイアログの表示を担当しているのがnavMyPutFile()ルーチンですが、このルーチンの中でも、NavPutFile()というNavigation Service APIが利用されます。このnavMyPutFile()やNavPutFile()については、次回に詳しく解説したいと思います。

    short saveCatalogFile( WindowRef window )
    {
        Str255   title;
        short    ret=1;
        FSSpec   fsc;
    
        if( ! getWFSSpec( window,&fsc ) )      // すでにファイルへ保存されているか?
            ret=saveObjectFile( window,&fsc ); // その場合にはFSSpecを得て上書き保存
        else
        {                                      // まだファイルに保存されていない...
            GetWTitle( window,title );         // 仮のドキュメント名を得る
            if( ! navMyPutFile( title,&fsc ) ) // ファイル保存ダイアログを表示
            {
                if( ! saveObjectFile( window,&fsc ) ) // 得たFSSpecを使い新規保存
                {
                    SetWTitle( window,fsc.name ); // ドキュメント名を再設定
                    setWFSSpec( window,&fsc );    // FSSpecをWcore構造体に保存
                    ret=0;
                }
            }
        }
        if( ret==0 )
            SetWindowModified( window,0 );        // 編集済みドキュメントとする
        return( ret );
    }
    


    NavDialogOptions構造体の詳しい内容や、その中で定義されているNavDialogOptionFlagsの種類と機能については、Universal InterfacesのNavigation.hを参照してみてください。次回は、Navigation Serviceの話の続きとなります。navMyPutFile()から呼ばれているNavPutFile()を含め、いくつかのNavigation Service APIの使用方法を解説したいと思います。

    つづく

    「Behind the WebObjects」  第34回  田畑 英和

     さて今年最後の連載になりますが、今回はデバッグ出力について取り上げてみたいと思います。プログラムが意図したとおりに動作しない場合はデバッグ用の出力をおこない、正しいデータがやりとりされているかを確認することが重要になります。

    Formデータの出力

     まずはHTML Formの出力についてみてみます。クライアントから送信されてきたFormデータを出力する場合は以下のようなコードを追加します。特定のコンポーネントに対するデータのみを出力する場合は、該当するコンポーネントに、すべてのFormデータを出力する場合はApplication.javaにこのメソッドを追加してください。このときsuperを呼び出すのを忘れないようにしてください。

    ・Formデータの出力

         public void takeValuesFromRequest(WORequest aRequest,
                                                   WOContext aContext) {
             System.out.println(aRequest);
    
             super.takeValuesFromRequest(aRequest, aContext);
         }
    


     これでクライアントから送信されてきたFormデータを出力できますが、Form以外のデータ(HTTPのヘッダー情報など)も一緒に出力されてしまいますので、Formデータのみを出力できるようにコードを書き換えてみます。

    ・Formデータの出力(改)

         public void takeValuesFromRequest(WORequest aRequest,
                                                   WOContext aContext) {
             NSArray allKeys = aRequest.formValueKeys();
             for(int i = 0 ; i < allKeys.count() ; i++) {
                 String aKey = (String)allKeys.objectAtIndex(i);
                 System.out.println(aKey + " : "
                                     + aRequest.formValueForKey(aKey));
              }
    
             super.takeValuesFromRequest(aRequest, aContext);
         }
    


    ・Formデータの出力結果
    3.3 : Match
    3.1 : The

     FormデータのみをKeyとValueのペアとして出力できるようになりましたが、キーの値が"3.3", "3.1"といった機械的な値になっているためデバッグ情報としては少し分かりにくいです。これはWebObjectsが動的にHTMLを生成するときに、Formエレメントの"name"属性を自動的に生成するためです。
     WebObjects Builderで各Formエレメントの"name"属性を明示的に設定しておけば、次のように分かりやすくFormデータを出力することができます。

    ・Formデータの出力結果(改)
    title : The
    submit : Match

    ヘッダー情報の出力

     次にヘッダー情報の出力をおこなってみましょう。takeValuesFromRequestはFormデータの送信がおこなわれたときにしか呼び出されませんので、今回はリクエスト時に必ず呼び出されるawakeを利用してみたいと思います。

         public void awake() {
             super.awake();
    
             NSArray allKeys = context().request().headerKeys();
             for(int i = 0 ; i < allKeys.count() ; i++) {
                 String aKey = (String)allKeys.objectAtIndex(i);
                 System.out.println(aKey + " : "
                                 + context().request().headerForKey(aKey));
             }
         }
    


     これでブラウザの"user-agent"などの情報を取得することができます。今回はデバッグ用の出力ということで解説をしていますが、これらのヘッダー情報を実際の処理に利用することも可能です。たとえば"user-agent"によって処理を切り替えるような応用が考えられます。

    リクエストーレスポンスデータのダンプ

     今回紹介したコードを利用すれば任意のタイミングで、必要な情報を出力することができますが、すべてのリクエストとレスポンスデータをヘッダーも含めてファイルに書き出すことができます。
     起動引数の"WORecordingPath"で任意のパスを指定すれば、そのパスにリクエストとレスポンスごとのテキストファイルが作成されます。このときファイル名には自動的に連番が付けられます。

    ・起動引数の指定
    -WORecordingPath /tmp/WOLog

    ・ダンプされたファイル
    Host:/tmp/WOLog.rec tabata$ ls
    0000-request 0001-request 0002-request
    0000-response 0001-response 0002-response

    SQLの出力

     WebObjectsではEOFを利用してデータベースアクセスをおこなうため、通常はSQLを直接扱いませんが、実際にはEOFの内部で必要に応じてSQLが自動生成されています。
     WebObjectsのロギングの機能にはSQLをログ出力する機能がありますので、Application.javaのコンストラクタに以下のコードを追加しておけば、アプリケーション内で生成されるすべてのSQLを出力することができます。

    ・SQLの出力
    NSLog.allowDebugLoggingForGroups(NSLog.DebugGroupSQLGeneration);
    NSLog.allowDebugLoggingForGroups(NSLog.DebugGroupDatabaseAccess);

     このようにして出力したSQLはパフォーマンスのチューニング時に重要な情報になりますので、EOFを使用する場合でもSQLの知識があったほうが役に立つでしょう。

    まとめ

     WebObjectsにはデバッグ用の出力に役立つAPIが用意されていますし、JavaにはLog4jのようなロギングのライブラリがありますので、これらを活用すれば効率よくデバッグ作業がおこなえるようになります。
     コーディングをおこなってアプリケーションを実行しているだけでは、問題が発生してもなかなか原因が分からないことがありますので、今回紹介した方法をぜひご利用ください。それでは皆様よいお年を!!

    ニュース・解説

    ★今週は開発関連のニュースがありませんでした。

    MOSAからのお知らせと編集後記は割愛します

    MOSA Developer News   略称[MOSADeN=モサ伝]
    Apple、Mac OSは米国アップルコンピュータ社の登録商標です。またそのほかの各製品名等はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    特定非営利活動法人MOSA  http://www.mosa.gr.jp/
    Copyright (C)2004-2006 MOSA. All rights reserved.

  • MOSA Developer News[MOSADeN=モサ伝]第141号

    2004-12-21

    目次

    • SqueakではじめるSmalltalk入門   第23回  鷲見 正人
    • 藤本裕之のプログラミング夜話 #59
    • 高橋真人の「プログラミング指南」  第58回
    • ニュース・解説

    SqueakではじめるSmalltalk入門   第23回  鷲見正人

     本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。今回はメソッドの再定義、つまりオーバーライドです。

    a StockAccountもa BankAccount同様、「balance」あるいは「balance: …」というメッセージを受けとることができます。ただ、a BankAccountのときとその振る舞いは異なります。つまり“多態”するわけです。

    a StockAccountにとって、「balance」というメッセージを受けて返すべき値は、インスタンス変数balanceの値【註1】ではなく、新しく設けられたインスタンス変数pricePerShareとnumSharesの積でなけければいけません。同様に、メッセージ「balance: …」に対しては、pricePerShareの単価で購入できるぶんの株数をnumSharesに設定すること、がそれに相応しい振る舞いとなります。なお、ここでは簡単のため、株数に端数も許すことにしています。

    balance
      ^ self pricePerShare * self numShares
    
    balance: aNumber
      self numShares: aNumber asFloat / self pricePerShare
    


     メッセージasFloatは、主に整数(an Integer)などに対して送信することで等価の浮動小数点数(a Float)を返します。これは、Integer >> #/ がan Integerをパラメータに取るとき、分数(a Fraction)を生成してしまうので、こうした状況を防ぐための処置です。参考まで、次にInteger >> #/の定義を転載しておきます。【註2】

    Integer >> / aNumber
      | quoRem |
      aNumber isInteger ifTrue:
        [quoRem _ self digitDiv: aNumber abs neg: self negative ~~
    aNumber negative.
        (quoRem at: 2) = 0
          ifTrue: [^ (quoRem at: 1) normalize]
          ifFalse: [^ (Fraction numerator: self denominator: aNumber)
    reduced]].
      ^ aNumber adaptToInteger: self andSend: #/

     さて、実はこれでStockAccountの定義は完了です。そう、#deposit:と#withdraw:は再定義の必要はないのです。論より証拠。実際に試してみることにしましょう。

    | stock |
    World findATranscript: nil.           "transcriptを開く"
    stock _ StockAccount new.             "a StockAccount作成"
    stock balance: 300.                   "300円預金"
    Transcript cr; show: stock balance.   "残高照会   => 300.0 "
    Transcript cr; show: stock numShares. "株数に換算 => 10.0 "
    stock deposit: 90.                    "90円預入"
    Transcript cr; show: stock balance.   "残高照会   => 390.0 "
    Transcript cr; show: stock numShares. "株数に換算 => 13.0 "
    stock withdraw: 240.                  "240円払戻"
    Transcript cr; show: stock balance.   "残高照会   => 150.0 "
    Transcript cr; show: stock numShares. "株数に換算 => 5.0 "
    stock withdraw: 180.                  "180円払戻"
    Transcript cr; show: stock balance.   "残高照会   => 0.0 "
    Transcript cr; show: stock numShares. "株数に換算 => 0.0 "
    


     なぜこのようなことになるのかについては、次回、解説します。

    註1:サブクラスには、スーパークラスのメソッドだけでなく、そこで定義されたインスタンス変数も継承されるので、a StockAccountには本来無用なインスタンス変数balanceも継承されてしまっています。継承させる属性を取捨選択するための言語機能が備えられていないことは、Smalltalkでクラス指向、つまり「C++タイプのオブジェクト指向」をすることが難しいことを意味します。純粋なクラス指向で考えたとき、あれもない、これもない状態のSmalltalkは、かなり駄目なオブジェクト指向言語なのです。

    註2:メソッドのメッセージパターンには、本来不要な「クラス名 >> 」という表現を追記して、そのメソッドがどのクラスに帰属するのかを明示的にすることがあります。以降の回ではサンプルメソッドにもこのような表記を用いることがあるので、もし、ブラウザなどにコピー&ペーストしてそのまま使用するときは、「クラス名 >> 」の部分は選択せずに、それを省いた残りをコピーするようにしてください。

    バックナンバー:
    http://squab.no-ip.com:8080/mosaren/

    藤本裕之のプログラミング夜話 #59

     再度承前。カッコの話の続きである。前回はカッコというモノが「その内包する部分をその外側から隔離して評価するという意味の表現」である、という結論を出して終わった。今回はこのシカツメらしい定義の意味するところ、カッコの存在意義の根源に筆を進めて行きたい。

    こんな話からはじめてみよう。カッコを多用することで一部に熱狂的排斥論者を持つLISPという言語がある。この言語の入門用によく出される課題に「animal」というタイトルの……まぁゲームと言ってよければゲーム、データベースと呼べばデータベースのプログラムを作る、というのがある。
     要はユーザーが頭に描いているanimal、すなわち動物をプログラムが当てるというものだ。LISPのコードをここに書いてもタイクツするヒトが大過労から……この誤変換面白いね、多かろうから、どういう構造かを散文的に解説する。御用とお急ぎでない方は、以下のURLで完成品の(英語だけど)ソースが手に入るのでご鑑賞くだされ。

    http://cvs.sourceforge.net/viewcvs.py/*checkout*/clocc/clocc/src/cllib/animals.lisp

     まず最初に一つの質問と二つの答えを用意する。例えば「その動物はクビが長いですか?」と質問し、ユーザーの「はい」あるいは「いいえ」という答えを待つ。ユーザーが「はい」と答えれば「その動物はキリンですか?」、「いいえ」なら「その動物はゾウですか?」と確認する。
     この確認にユーザーが「はい」と答えればセッションは終了、答えが「いいえ」の場合、プログラムは降参し、ユーザーにその動物の名前を入力してもらう。そして、たとえばそれが「フラミンゴ」だったとすると(なるほどフラミンゴだってオレやあなたよりは首が長い)プログラムはこう要求する。「キリンとフラミンゴを区別するための質問をひとつ教えてください」。
     そして次にこのプログラムが起動されたときは最初とは動作が変わっている。まず「その動物はクビが長いですか?」は同じだが、「はい」と答えると、さっきユーザーに教えてもらった次の質問を聞いてくるわけ。「その動物には羽がありますか?」とかね。
     ユーザーが誠実にこのプログラムの相手をすれば、プログラムは多くの動物に関する知識を集積することになる。

    このプログラムの根幹にあるロジックは単なる二分法である。全ての動物という集合を、とりあえずは「クビが長い動物とそれ以外」に分け、そのそれぞれのなかをまた入れ子のごとく「これこれこういうモノとそれ以外」で二分していくわけだ。
     諸星大二郎「孔子暗黒伝」の読者ならご存知のように、これはつまり中国古代、易経に観られる世界観である。まず最初に混沌とか太極とかいう一個の存在があり、これが陰陽(両儀という)に分かれる。そのそれぞれがまたニつに分かれて四象、また別れて八卦……これがあの「当るも八卦、当らぬも八卦」の八卦ですな。
     さて、この細分と統合に使われる便法がすなわちカッコである。万物は集合でありカッコはその部分集合を定義する道具、すなわち世界を分割する道具である。そして部分集合としてその外部から切り離される以上、その内側には切り離された妥当な理由が存在する。首が長いとか、胎生であるとか、染色体のペアがXYであるとか、全国共通学力試験における偏差値が60以下であるとか、いろいろね。
     こういう分割を我々は通常「分類」と言っている。
     そしてこれらの分類は全て(中には許しがたく差別的なものもあるが機能的には、ということね)、この混沌とした世界を「整理し理解しようとするココロミ」なのである。カッコが多いのは言い換えれば事態が執拗に分析されまくった証拠でもあるのであり(もちろん間違った分析である場合もあるが「執拗に」おこなわれたことに変わりはない)、プログラマたるものがそれを見て怖気をフルったりしてはいけないのである。
    (2004_12_16)

    高橋真人の「プログラミング指南」第58回

    UNIXとしてのMac OS X

    〜Perlについて(4)〜

     こんにちは、高橋真人です。
     さて、前回の配列とリストとは別のものだというお話をしましたが、Cを使っている方は、「そんなことは当たり前だろ」と思われるかもしれません。

    int array[] = {5, 26, 32, 79, 100};

    というコードがあった場合、代入の左辺であるarrayと右辺である{5, 26, 32, 79, 100}との関係で見れば、当然右辺のようなものを配列とは呼ばないでしょうからね。
     ところが、Perlを使い慣れてくると、リストと配列を同じ感覚で使えるケースが殊の外多いことに気づくのです。たとえば、

    $a = 10;
    $b = 20;
    $c = 30;
    @array = ($a, $b, $c);

    といったように、変数をカンマで区切ってからカッコで囲んでもリストになりますし、さらには、リストを左辺に置くこともできてしまうのです。例えば以下のような感じです。

    ($a, $b, $c) = @array;

     この場合、@arrayの保持している要素が、先頭から順に$a、$b、$cに代入されていきます。@arrayの要素数が3より多い場合には先頭の3個のみが代入され、3個よりも少ない場合には代入される値のないものにはundefという特殊な値が入ります。
     また、リストの特定の要素を[]で指定することもできます。

    $value = (5, 23, 7)[1];

     ここでは、$valueには23が入ります。さらに、Perlでは配列の末尾要素を-1で指定できますが、リストにおいても可能です。

    $value = (5, 23, 7)[-1];

     $valueには、リストの末尾要素である7が入るわけです。
     さらに、リストを返す演算子を利用すれば例えば「ファイルパスの末尾から2番目の要素を取り出す」なんてことも簡単にできます。

    $path = 'Macintosh HD:Users:mosa:Desktop:file.txt';
    $desktop = (split /:/, $path)[-2];

     これで、$desktopには’Desktop’が入ります。splitという演算子は、

    split DELIMITER, STRING

    という構文で使われる演算子で、文字列STRINGをDELIMITERで区切り、区切られた各要素をリストにして返すようになっています。
     ちなみに、DELIMITERの部分は「正規表現」という特殊な表記法を使いますが、これについてはまた機会を改めて説明します。

    このように、Perlしか知らない人にとっては、意外にリストと配列の区別というのは付きにくいものなのです。
     しかし、以上のような例を見ることで、かえってC/C++系の言語のベテランには納得がピンと来る方が多いのではないでしょうか。
     例えばCでも配列を返す関数に対してインデックス参照をすることが可能です。

    char array[256];
    char c;
    c = strcpy(array, "Hello")[1];

     strcpy()は、第2引数を第1引数にコピーするのが第一義的な目的なので、第1引数のポインタを返すことは普段あまり意識しませんが、このように書けば、ちゃんと文字列として機能するので[1]というインデックス参照によって2番目の要素を返すので、変数cには’e'が入るわけです。
     C++を使うようになると特に、この手の「一時的に作られて、すぐになくなる値」というものの存在を意識することが多くなりますが、結局これらの値は変数として存在するものではないので読み出し以外の操作はできません。
     同様に、Perlのリストも要素を操作する(つまり、読み出すだけではなく何らかの変更処理を伴う)演算子(関数)を適用することはできないのです。
     なので、

    @array = sort (5, 2, 9, 1);

    は、OKですが、

    @array = shift (5, 2, 9, 1);

    はエラーです。
     sort演算子は、引数を変更することなく、引数と同じ要素をソートされた形で返しますが、shift演算子は、先頭要素を返すと同時に引数のリストの第1要素を削除する仕組みになっているからです。

    ニュース・解説

    今週の解説担当:小池邦人

    Carbon ドキュメント & サンプル & SDK ナビゲーション(2004/12/17)

    【開発環境】

    Mac OS X 10.3.6の登場から1ヶ月ちょっとしか経っていませんが、早くも次のMac OS X 10.3.7が登場しました。ビデオカードのドライバ更新(バグ取り?)がメインの仕事のようです。Mac OS X 10.3.6で生んでしまったバグや積み残したバグの退治も行われているようです。今回のビデオカードのドライバの改良は、ゲームアプリケーションでの画面表示スピードの改善などには随分と効果があるようです。ところが、うちのNvidia GeForce 68000 GT DDLの表示速度をXBenchで測定してみると、以前に搭載してたビデオカード(何だっけ… ATI Radeon 9600 XTかな?)よりも悪いスコアのままで、10.3.6からあまり変化はありません(涙)。まあ、ベンチマークアプリの癖もありますので断言はできませんが(自作アプリでは高速だなと思う時もあるので…)、まだまだビデオカードの潜在能力を100%引き出すほどドライバがチューニングされていないのかもしれません?Tigerに期待したいと思います。

    Dashboard Widgetsの2回目のコンテストが開始されたようです。一回目ではあまり面白いWidgetsが集まらなかったのでしょうか(笑)。Tigerのプレビュー版でWidgetsを開発するためのSDKや解説資料は、ADCメンバーサイトにアップロードされています。また後述する「Tiger Developer Overview Series: Developing Dashboard Widgets」も大いに参考になるでしょう。賞品のiPodを狙ってみてください(バスケ君に続け!)

    http://developer.apple.com/macosx/tiger/dashboard/index.html?headlines

    【テクニカルドキュメント】

    前回から12月17日の期間中、Apple社のDocumentationサイトには新規ドキュメントがひとつも登録されませんでした。その代わり、Release Noteサイトには2つのドキュメントが追加されています。「AppleEvent Manager」は、Mac OS X 10.3でAppleEvent Managerに加えられた変更点が解説されています(結構重要)。またデベロッパ向け解説も2つ登録されています。前号で新居さんも紹介されている「Using Oracle JDeveloper on Mac OS X」は、OracleのJDeveloperをMac OS Xで利用する方法の解説です。

    「AppleEvent Manager」

    http://developer.apple.com/releasenotes/Carbon/AppleEvents.html

    「WebObjects 5.2 Release Notes」(PDFあり)

    http://developer.apple.com/documentation/WebObjects/ReleaseNotes/index.html

    「Using Oracle JDeveloper on Mac OS X」(解説)

    http://developer.apple.com/tools/jdeveloper.html

    「Tiger Developer Overview Series: Developing Dashboard Widgets」(解説)

    http://developer.apple.com/macosx/tiger/dashboard.html

    前回から12月17日の期間中、新規のテクニカルノートは2つ登録されました。
    「OpenGL Performance Optimization : The Basics」では、OpenGL APIに強く依存しているアプリケーションの最適化手順をProfiler、Driver Monitor、CHUDなどのツールの使い方を含めて詳しく解説しています、また「Mac OS X Debugging Magic」の方はプリントアウトすると27ページにもなる大作で、Mac OS Xのデバッグ方法の集大成です。両方とも関連デベロッパーにとっては必読のテクニカルノートです。TN2124の方は、前号の新居さんの記事も参照してみてください。

    TN2124「Mac OS X Debugging Magic」
    TN2093「OpenGL Performance Optimization : The Basics」

    http://developer.apple.com/technicalnotes/index-rev-date.html

    新しいテクニカルQ&Aの方は6つ登録されました。QA1355とQA1395は、新居さんが前号で紹介されています。

    QA1346「Finding an NSView’s current magnification」
    QA1353「NSOpenGLView redraw problems after a window is closed and re-opened」
    QA1395「Hang launching signed Applets from JavaScript」
    QA1355「Why aren’t my tracking rects working?」
    QA1374「Obtaining the name of an external MIDI Device from a MIDI Endpoint」
    QA1166「OpenGL Sample Code」

    http://developer.apple.com/technicalqas/index-rev-date.html

    【サンプルソースコード】

    前回から12月17日の期間中、Apple社のSample Codeサイトには、新しいサンプルソースコードが2つ登録されました。「QuickTimeMovieControlは、久しぶりに登録されたQuickTime関連のサンプルソースコードです。
    CreateMovieControl()を利用することでMovieの再生を行うCarbonアプリケーションの最新サンプルです。サンプルアプリのアイコンに注目しましょう(笑)。

    「DNSServiceMetaQuery」(Network関連)
    「QuickTimeMovieControl」(QuickTime関連)

    http://developer.apple.com/samplecode/index-rev-date.html

    【デベロップメント SDK】

    前回から12月17日の期間中、Apple社のSDKサイトには新しいSDKはひとつも登録されませんでした。

    http://developer.apple.com/sdk/

    MOSAからのお知らせと編集後記は割愛します

    MOSA Developer News   略称[MOSADeN=モサ伝]
    Apple、Mac OSは米国アップルコンピュータ社の登録商標です。またそのほか

    各製品名等はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    特定非営利活動法人MOSA  http://www.mosa.gr.jp/
    Copyright (C)2004-2006 MOSA. All rights reserved.

  • MOSA Developer News[MOSADeN=モサ伝]第140号

    2004-12-14

    目次

    • SqueakではじめるSmalltalk入門  第22回  鷲見 正人
    • 小池邦人の「Carbon API 徒然草」
    • 「Behind the WebObjects」    第33回  田畑 英和
    • ニュース・解説

    SqueakではじめるSmalltalk入門   第22回  鷲見正人

     本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。今回から、先に作成したBankAccountのサブクラスとしてStockAccountを定義します。

    預金を扱うBankAccountに対し、今回作成するStockAccountは、株式口座オブジェクトを定義するクラスとして位置づけることにします。簡単のため、扱う株は一種類、つまり株単価は(可変ですが)一意的とします。a StockAccountの振る舞いはa BankAccountとまったく同じです。つまり、メッセージ「deposit: …」で入金し、「withdraw: …」で払い戻しできます。違うのは、内部状態として、株単価と株数を、それぞれインスタンス変数pricePerShare、numSharesに束縛していること、そして出納の際、その金額に見合った株が売買される(保有株数が減ったり増えたりする)ことです。では早速はじめましょう。

    まず、思い出していただきたいのは、BankAccountの定義とその手順です。クラスカテゴリペインに新しいクラスカテゴリ「Category-MosaDen」を追加し、その時コードペインに表示されるテンプレートを次のように書き換えることでBankAccountを定義しました。

    Object subclass: #BankAccount
      instanceVariableNames: 'balance'
      classVariableNames: ''
      poolDictionaries: ''
      category: 'Category-MosaDen'

     これは、Objectというクラスに対する「subclass: #BankAccount instanceVariableNames: ‘balance’ classVariableNames: ” poolDictionaries: ” category: ‘Category-MosaDen’」という長いメッセージ送信式になっている話もしました。改めてこのメッセージを読み下すと、Objectというクラスに対して、そのサブクラスとして#BankAccountという名前をこれこれの仕様で作りなさい…ということになります【註】。StockAccountは、BankAccountのサブクラスなのでこの応用で大丈夫ですね。大まかには、レシーバをObjectからBankAccountに、作成するサブクラス名を#StockAccountに、各種仕様を相応しいものに差し替えればよいわけです。

    まず、クラスペインで選択されているBankAccountをクリックして選択を解除します。もし、ブラウザを閉じてしまっていたら、BankAccountをbrowse it(cmd-B)して開いてから、改めて選択を解除してください。すると、コードペインにはクラスカテゴリを新設したときと同様にクラス定義用のテンプレートが現われます。これを、先の方針にしたがって書き換え、accept (cmd-S)します。

    BankAccount subclass: #StockAccount
      instanceVariableNames: 'pricePerShare numShares'
      classVariableNames: ''
      poolDictionaries: ''
      category: 'Category-MosaDen'

     acceptと同時に、クラスペインにStockAccountが追加されます。

    [fig.A]StockAccountがクラスペインに追加されたところ
    http://squab.no-ip.com:8080/mosaren/uploads/22a.png

     手始めに、お馴染みのアクセッサを定義しましょう。インスタンス変数pricePerShare、numSharesと同名のゲッター(値を取得するためのメソッド)と、引数をひとつ取る、つまりコロンを付したセッター(値設定用のメソッド)を定義します。まず、メソッドカテゴリを新設します。

    メソッドカテゴリペインの黄ボタンメニューから「new category…」を選び、続けて現われるポップアップから「accessing」を選びます。このポップアップには、Object以外のスーパークラスで使用済みのメソッドカテゴリが一覧でき、新規カテゴリ名として採択できるようになっているので、スーパークラスのメソッドカテゴリと同様のカテゴリを追加するときは、new…でいちいち再入力せずに済ませることができます。

    accessingカテゴリ追加と同時に、下のコードペインにはメソッドテンプレートが選択状態になって現われるので、マウスカーソルをコードペインに移動してアクティベート(選択状態を確認)した後、次のコードをこのメールからコピー&ペーストします。念のため忘れずにシフト黄ボタンメニューからpretty printしてから、accept (cmd-S)して登録します。

    pricePerShare: aNumber
    pricePerShare _ aNumber

     次は#numShares:ですが、ここで、ちょっとした編集テクニックを紹介します。#numShares:の定義は次のようなものです。

    numShares: aNumber
    numShares _ aNumber

     これは先の#pricePerShare:において「pricePerShare」を「numShares」に全置換したものと同一です。そこで、先頭の「pricePerShare」を選択して「numShares」と入力して置き換えた後、続けて、cmd-Jとタイプしてみてください。これはagainと呼ばれるSmalltalkシステムに特徴的なテキスト編集機能で、直前の置き換え操作を次の出現箇所に適用します。大変便利な機能なのですが、残念ながらMacに継承されることはありませんでした。なお、置き換えたい箇所が残り2カ所以上ある場合は、shift+cmd-Jとタイプします。

    ゲッターは、BankAccount >> #balance同様、遅延初期化にしておきましょう。numSharesは未定義時、balance同様に0でよいのですが、pricePerShareは0というわけにはいかないので、適当に30くらいにしておきます。

    pricePerShare
      ^ pricePerShare ifNil: [pricePerShare _ 30]
    
    numShares
      ^ numShares ifNil: [numShares _ 0]

     次回は、#balance:、#balanceを再定義してStockAccountを完成させます。

    註:記憶力の良いかたは、スーパークラスがサブクラスを作成することに対して、さっそく疑問を持たれたことと思います。なぜなら、クラスはメタクラスのインスタンスであり、サブクラスを作るにしても、そのメタクラスにnewを送信するのがスジで、継承関係こそあれ、赤の他人のスーパークラスがサブクラスを生じさせるのは相応しくない…と考えることができるからです。

    結論から申し上げるとその考え方で合っています。ただ、サブクラス定義時点では、サブクラスのメタクラスは存在せず、まずこれから作る必要があります。メタクラスのクラスはMetaclassなので、これのインスタンスとしてStockAccount classがまず生じ、そこから改めてStockAccountが作成されます。スーパークラスへのメッセージ送信はこうした一連の作業のきっかけ作りに過ぎないのです。

    バックナンバー:
    http://squab.no-ip.com:8080/mosaren/

    小池邦人の「Carbon API 徒然草」

    Carbon API 徒然草(2004/12/10)

    〜 データブラウザ・コールバックルーチン 〜

    今回は、SetDataBrowserCallbacks()で登録しておいた2種類のコールバックルーチン、mySetGetItemData()とmyNotification()について詳しく解説したいと思います。

    コールバックルーチンの中身の説明をする前に、先んじて準備しておいたデータをどのようにデータブラウザへ新規登録するのかを見てみます。以下が、Object構造体に保存されている画像ファイル情報を一括してデータブラウザに登録するaddItemDataBrowser()ルーチンです(実はデータ本体は登録しないのだが…)。ちなみに、今回のアプリケーションでは登録できる画像ファイル数は1000個までに制限されています。

    #define    BROW_ID    100    // DataBrowserのControl ID
    #define    MAX_FILE   1000   // 登録できる画像ファイルの最大数
    
    short addItemDataBrowser( WindowRef window )
    {
        DataBrowserItemID    item[MAX_FILE];
        ObjectPtr            list[MAX_FILE];
        unsigned long        ct1,ct,i;
        ControlRef           browser;
        short                ret=1;
    
        collectObject( window,list,&ct ); // 登録画像ファイルのObject構造体を集める
        setWObjList( window,ct,list ); //カタログウィンドウのWInfo構造体に保存する
        for( i=0;i<ct;i++ ) // DataBrowserItemIDにアイテム番号(参照番号)を代入する
            item[i]=i+1;
        getMyControlRef( window,BROW_ID,&browser ); // DataBrowserのControlRefを得る
        GetDataBrowserItemCount( browser,kDataBrowserNoItem,0,
                                                    kDataBrowserItemAnyState,&ct1 );
        // 現在DataBrowserに登録されているアイテムの個数を得る
        RemoveDataBrowserItems( browser,kDataBrowserNoItem,ct1,item,
                                                       kDataBrowserItemNoProperty );
        // 現在DataBrowserに登録されているアイテムを削除する
    
        if( ct ) // DataBrowserに登録すべき画像ファイルがある場合のみ...
        {
            AddDataBrowserItems( browser,kDataBrowserNoItem,ct,item,
                                                       kDataBrowserItemNoProperty );
            // DataBrowserにファイル個数分のアイテム番号をセットする
            SetDataBrowserSelectedItems(browser,1,&item[ct-1],kDataBrowserItemsAdd);
            // 登録された一番最後のアイテムを選択(セレクション)する
            ret=0;
        }
        DrawOneControl( browser ); // DataBrowser自身を再描画する
        return( ret );
    }
    


    まずは、collectObject()により、いくつの画像ファイルを登録するのか?そのObject構造体の個数を得ます。Object構造体にはファイル情報(ファイルタイプとFSSpec構造体)が含まれており、それらはすでにドキュメントの読み込み、ファイルやフォルダのドラッグ&ドロップなどにより作成されています。

    最初に、配列番号に1を足した値をアイテム番号(参照番号)としてitem[MAX_FILE]に代入しておきます。続いてGetDataBrowserItemCount()とRemoveDataBrowserItems()により、現状のリスト内容をすべて削除し新規登録に備えます。AddDataBrowserItems()により画像ファイル個数分(ct)のアイテム番号をデータブラウザに追加登録したら、SetDataBrowserSelectedItems()で一番最後のアイテムを選択(セレクション)し作業は終了します。

    AddDataBrowserItems()の引き数を見てみると、アイテム番号の方は渡されていますが、Object構造体自体は渡されてはいません。では、それはどの時点で渡されて表示に使われるのでしょうか? 実は、実際にデータを表示する場合には、先んじて登録したアイテム番号をうまく利用することになります。その仕事を担当しているのが、ひとつめのコールバックルーチンmySetGetItemData()です。

    pascal OSStatus mySetGetItemData( ControlRef browser,DataBrowserItemID itemID,
                    DataBrowserPropertyID property,DataBrowserItemDataRef itemData,
                                                              Boolean changeValue )
    {
        short        ret=0;
        CFStringRef  cref;
        IconRef      iref;
        ObjectPtr    optr;
        short        lav;
        Str255       str;
    
        if( ! changeValue )
        {
            getWObject( GetControlOwner( browser ),itemID-1,&optr );
            // itemID(アイテム番号)に対応するObject構造体(ファイル情報)を得る
            switch( property )
            {
                case 'name': // 表示対象カラムがファイル名の場合
    
                    GetIconRefFromFile( &optr->o_fsc,&iref,&lav );
                    // 画像ファイルのアイコンのIconRefを得る
                    SetDataBrowserItemDataIcon( itemData,iref );
                    // DataBrowserの'name'カラムの先頭にアイコンを表示
                    if( cref=CFStringCreateWithPascalString( NULL,optr->o_fsc.name,
                                                    CFStringGetSystemEncoding() ) )
                    // ファイル名をStr255からCFStringRefに変換
                    {
                        SetDataBrowserItemDataText( itemData,cref );
                        // DataBrowserの'name'カラムにファイル名を表示
                        CFRelease( cref );
                    }
                    break;
    
                case 'type': // 表示対象カラムがファイルタイプの場合
    
                    *str=4;
                    BlockMoveData( &optr->o_type,str+1,4L );
                    if( cref=CFStringCreateWithPascalString( NULL,str,
                                                   CFStringGetSystemEncoding() ) )
                    // ファイルタイプををStr255からCFStringRefに変換
    
                    {
                        SetDataBrowserItemDataText( itemData,cref );
                        // DataBrowserにのtypeカラムにファイルタイプを表示
                        CFRelease( cref );
                    }
                    break;
    
                default:
    
                    ret=errDataBrowserPropertyNotSupported;
                    break;
            }
        }
        return( ret );
    }
    


    このコールバックルーチンには、リスト表示させるべきデータをデータブラウザに「渡す処理」(セット)と、表示されているデータを「得る処理」(ゲット)を実装します。引き数のchangeValueがfalseならば、データを渡すことを意味し、逆にtrueであれば、データを得ることを意味します。今回は渡す処理のみが実装されています。例えば、スクロールでリストの表示領域が変更された場合には、このコールバックルーチンが呼び出され、表示すべきデータの再セットを促すわけです。ファイル情報のうち、どのデータをセットすべきかは、引き数のカラムタイプ(property)とアイテム番号(itemID)から判断します。表示すべきファイル名とファイルタイプはObject構造体に保存されており、それはアイテム番号により1対1で参照することが可能です。アイテム番号からObject構造体を得るのには、自作のgetWObject()ルーチンを利用します。

    次に、もう片方のコールバックルーチンmyNotification()を紹介します。こちらのコールバックルーチンは、ユーザがデータブラウザに対して何らかの操作を実行した時に呼ばれます。つまり、データブラウザのデータ内容や表示状態に変化させるイベントが発生した場合に、その種類をDataBrowserItemNotification(message)に代入して教えてくれるわけです。

    pascal void myNotification( ControlRef browser,DataBrowserItemID itemID,
                                              DataBrowserItemNotification message )
    {
        WindowRef    wptr,wptr1;
        ObjectPtr    optr;
    
        wptr=GetControlOwner( browser ); // カタログウィンドウのWindowRefを得る
        getWObject( wptr,itemID-1,&optr ); // アイテム番号から対象Object構造体を得る
        switch( message )
        {
            case kDataBrowserSelectionSetChanged: // 選択アイテムが切り替わった
    
                mainteCatalogWindow( wptr ); // ボタン表示や画像表示をメンテナンス
                break;
    
            case kDataBrowserItemDoubleClicked: // アイテムがダブルクリックされた
    
                if( getModifiers()&optionKey ) // オプションキーが押されている場合
                    launchApplication( &optr->o_fsc ); // 画像に対応するアプリを起動
                else
                    openViwerWindow( wptr,&optr->o_fsc,&wptr1 ); // 画像をオープン
                break;
        }
    }
    


    例えば、アイテムのダブルクリックでその画像ファイルをオープンさせたい時に、この仕組みを利用しています。本アプリケーションでは、アイテムのセレクション(選択範囲)の変更(kDataBrowserSelectionSetChanged)と、マウスによるアイテムのダブルクリック(kDataBrowserItemDoubleClicked)の2種類のイベントに対応しています。こうしたイベントに対するメッセージとしては、アイテムの追加(kDataBrowserItemAdded)や、アイテムの削除(kDataBrowserItemRemoved)など、いくつもの種類が用意されていますので、それぞれの詳しい内容についてはControlDefinitions.hを参照してください。

    次回は、メインウィンドウを閉じるときに呼ぶcloseCatalogWindow()ルーチンを調べてみます。内部で使われている自作ルーチンだけではなく、データブラウザに登録されているファイル一覧の保存と読み込みを担当しているルーチンについても解説する予定です。

    つづく

    「Behind the WebObjects」  第33回  田畑 英和

     前回はカスタムEOの実装方法を取り上げ、データの初期化について解説しました。今回はデータの正当性の検証方法について説明したいと思います。

    データの正当性の検証

     アプリケーション上では様々なデータを扱うことになりますが、個々のデータが適切な値であることを検証しなければならないことが多々あります。例えば、年齢のデータを扱う場合は0以上になるでしょうし、メールアドレスには”@”が含まれる必要がありますし、日本の郵便番号は3+4の7桁の数値になります。もしデータの正当性をチェックしなければ、不正なデータが混入する可能性があり、そのデータを利用した処理に影響が出るおそれがあります。

    不正なデータが混入することを防ぐには、入力されたデータの正当性を検証する必要があります。正当性を検証する方法はいくつか考えられますが、例えばJavaScriptを用いてWebブラウザ上で入力データをチェックすることが考えられます。この方法ですとクライアント上で正当性の検証がおこなえるため、サーバとやりとりすることなくデータをチェックすることができます。
     またモデルファイル上でもNullのチェック、文字数(byte数)の上限チェック、リレーションのチェックなどを設定することができます。モデル上での制約にひっかかった場合はExceptionが発生しデータベースに不正なデータが保存されるのを防止できます。これらのチェックはEOModeler上で簡単に設定することができます。

    このようにクライアント側での入力データチェックや、モデルファイルを用いた入力データのチェックがおこなえますが、カスタムEOに正当性検証用のロジックを埋め込んでおくこともできます。カスタムEOへのロジック追加になりますのでJavaプログラミングをおこなうことになります。

    カスタムEOでの正当性の検証

     データを初期化するメソッドとして前回awakeFromInsertion()を紹介しましたが、データの正当性検証用のメソッドもあらかじめ用意されています。このメソッドは、データを保存するときに(EOEditingContextのsaveChanges()を実行したとき)に自動的に呼び出されます。

    ・データの正当性検証用メソッド

         public void validateForSave()
                         throws NSValidation.ValidationException

     独自の正当性検証ロジックを組み込むには、次のようにカスタムEOクラスでこのメソッドをオーバーライドします。このときまずはsuper()を用いて親クラスのvalidateForSave()を呼び出してから、独自の検証処理を実行するようにします。
     もし検証結果が正しくない場合は、NSValidation.ValidationExceptionの例外を発生させるように実装します。

         public void validateForSave()
                             throws NSValidation.ValidationException {
             super.validateForSave();
    
             // 検証処理
            if(checkError() == false) {
                   throw new NSValidation.ValidationException("Error");
             }
         }
    
         private boolean checkError() {
             // 検証ロジック
         }
    

     このようなコードを実装しておけば、saveChanges()の実行時に自動的に呼び出され、任意の検証処理をEOに対して適用することができます。さらに必要に応じてこのメソッドを直接実行すれば、任意のタイミングで検証処理を明示的に実行することもできます。

    プロパティレベルでの正当性の検証

     validateForSave()はEOレベルでの正当性を検証するメソッドですが、各プロパティ(アトリビュート)レベルでの検証用ロジックを実装することもできます。各アトリビュートごとに以下のメソッドを実装します。
     このとき”validateKey”の”Key”の部分を、実際に検証をおこないたいアトリビュート名に書き換えたメソッドを実装します。アトリビュート名の頭文字は大文字にしてください。

    ・プロパティレベルの正当性検証用メソッド

         public Object validateKey(Object aValue) throws
                         throws NSValidation.ValidationException
    


     例えばrevenueアトリビュートを検証するメソッドは以下のように実装することができます。プロパティレベルの検証メソッドは対応するアトリビュートの値が変更される前に呼び出されます。さらにvalidateForSave()を実行したときにも、super.validateForSave()からプロパティレベルの検証メソッドが呼び出されます。

         public BigDecimal validateRevenue(Object aValue)
                             throws NSValidation.ValidationException {
             BigDecimal revenue;
             if (aValue instanceof BigDecimal) {
                 revenue = (BigDecimal)aValue;
             } else {
                 throw new NSValidation.ValidationException("Error1");
             }
    
             if(revenue.intValue() < 0) {
                 throw new NSValidation.ValidationException("Error2");
             }
    
             return revenue;
         }
    

    まとめ

     今回紹介したメソッドを用いれば、不正なデータの入力を防ぐことができ、正しいデータのみがデータベースに保存できるようになります。ただしWebアプリケーションの場合、サーバ側ですべての正当性の検証をおこなうとなるとクライアントとのトランザクションが増えてしまいますので、JavaScriptを用いたクライアント側での検証処理と組み合わせるなどの工夫をおこなえば、効果的な検証処理を実現することができます

    ニュース・解説

    今週の解説担当:新居 雅行

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃Mac OS Xでのデバッグ手法を1つにまとめた文書が公開
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Technical Noteとして、Mac OS Xのさまざまなデバッグ手法について解説する文書が公開されている。Crash ReporterやBSDレイヤで利用できる機能、さらにはgdbを使った方法など、デバッグについての情報がひとつにまとまった文書となっている。CarbonやCocoaでは内部動作をトレースするような機能の説明がある。Macでプログラミングをしている人は、かならずどこかに興味ある情報が見つかるだろう。

    Technical Note TN2124: Mac OS X Debugging Magic
    http://developer.apple.com/technotes/tn2004/tn2124.html

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃サイン付きアプレットとLiveConnect
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Java 1.4.2 Update 2では、LiveConnectを使ってJavaScriptからJavaアプレットを呼び出したとき、そのアプレットがサイン付きで認証される前に呼び出しがあった場合にハングアップしてしまう。これを回避するには、LiveConnect利用をする前に、あらかじめサイン付きアプレットの認証を終わらせておくようにすればよい。サンプルプログラムも掲載されている。

    Technical Q&A 1395: Hang launching signed Applets from JavaScript
    http://developer.apple.com/qa/qa2004/qa1395.html

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃マウスポインタ変化のための矩形領域を設定する
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    マウスポインタを位置によって形状を変えるために、矩形領域をaddTrackingRectメソッドで登録したけど何もおこらないという問題に対する回答が掲載されている。これは、ビューをウインドウに登録する前にマウス応答のための矩形領域を追加するために発生すると解説されている。
    addTrackingRectメソッドを、viewDidMoveToWindowあるいはawakefromNibメソッドで利用するなど、適切な順序で利用するようにすればよい。

    Technical Q&A: Why aren't my tracking rects working?
    http://developer.apple.com/qa/qa2004/qa1355.html

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃OracleのJDeveloperをMac OS Xで使う
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ADCのサイトで、Oracleがフリーで配布している開発ツールのJDeveloperをMac OS Xで利用する方法が記事で紹介されている。Oracle Databaseの利用が前提となるが、現在もOracle Database 10g Early Adopters Release 2が配布されているので、それを使うことが前提となる。

    Using Oracle JDeveloper on Mac OS X
    http://developer.apple.com/tools/jdeveloper.html

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃FileMakerのデータベースとSQLを同期するツール
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Garrison Computer Servicesは、FileMakerのデータベースとSQLデータベースの内容を同期させるツール「fmSQL Synch v1.0」をリリースした。少しの修正で同期ができるとしている。また、FileMakerから他のデータベースへの移行あるいは逆への移行にも使えるツールである。ただし、FileMaker Pro 4以降対応ながら、FileMaker Pro 7には対応していない。次のリリースでVer.7への対応を行う予定としている。価格はシングルユーザ版で$129などとなっている。なお、同社では、さまざまな稼働環境での同期ツールを今後もリリースする予定である。

    fmSQL Synch v1.0
    http://www.garrison.com.au/products/fmsql_synch.html

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    ┃VNCを用いたテスティングツールがアップデート
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Redstone Softwareは、ネットワーク越しに他のコンピュータをコントロールすることで、GUIの自動テストを行うツール「Eggplant 2.0」をリリースした。テスト手続きはSenseTalkという独自の言語を使って記述するがシンプルで学習しやすいものとしている。そして、VNCのプロトコルを用いて他のコンピュータをコントロールするため、Macだけでなく、Windowsについてもテスティングが可能となっている。バージョンアップにより、テスト機能の強化とともに、同社が配布しているOSXvncを使えば、テスト環境の存在をRendezvousを通じて参照できるようになる。

    Eggplant
    http://www.redstonesoftware.com/whatiseggplant.html

    MOSAからのお知らせと編集後記は割愛します

    MOSA Developer News   略称[MOSADeN=モサ伝]
    Apple、Mac OSは米国アップルコンピュータ社の登録商標です。またそのほかの各製品名等はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    特定非営利活動法人MOSA  http://www.mosa.gr.jp/
    Copyright (C)2004-2006 MOSA. All rights reserved.

  • MOSA Developer News[MOSADeN=モサ伝]第139号

    2004-12-07

    目次

    • 「特定非営利活動法人MOSA」設立にあたって   MOSA会長 矢野 孝一
    • SqueakではじめるSmalltalk入門   第21回  鷲見 正人
    • 藤本裕之のプログラミング夜話 #58
    • 高橋真人の「プログラミング指南」  第57回
    • ニュース・解説

    「特定非営利活動法人MOSA」設立にあたって

     任意団体としてのスタートから10年。11年目の今年、NPO法人として新たなスタートをする事は、まさに大きな節目となりました。
     我々を取り巻く環境も10年前とは大きく変わり、オープンソースの潮流が益々拡大しております。我々の活動も、そうした新たな動向に沿いながらさらに充実、発展して行くことを願っています。
     会員の皆様や協賛企業の方々のご理解とご協力により、MOSAの活動が今まで以上に活性化していきます様、理事一同努力して参りますので、宜しくお願いいたします。

            2004年12月  特定非営利活動法人MOSA 会長 矢野 孝一

    設立総会/懇親会開催のご報告

     2004年12月1日からのNPO法人活動開始にあたり、12月3日(金)、東京都目黒の「東京都庭園美術館大ホール」におきまして、「特定非営利活動法人MOSA
     設立総会/懇親会」を開催いたしました。

     当日は66名が参加、設立総会も無事終了し、懇親会においてはアップルコンピュータ株式会社 代表取締役 兼 米国Appleマーケティング担当バイスプレジデント前刀禎明氏、社団法人日本コンピュータシステム販売店協会 専務理事 弓削芳光氏よりご祝辞を頂戴しました。
     また、株式会社アクト・ツー、アップルコンピュータ株式会社、マイクロソフト株式会社、マイクロソフト プロダクト デベロップメント リミテッド各社よりお花をお贈りいただきました。
     まずは、この場をお借りして厚く御礼申し上げます。
     設立総会/懇親会の模様は、こちらに掲載しております。
    http://www.mosa.gr.jp/?p=147
                                  MOSA事務局

    SqueakではじめるSmalltalk入門   第21回  鷲見 正人

     本連載では、名前は知っていてもなかなか触れる機会のないSmalltalkについて、最近話題のSqueakシステムを使って紹介しています。今回はオブジェクト指向の“種類”と継承の関係についてです。

    継承とは、端的には、定義済みのクラスからの差分を記述するだけで、新しいクラスを定義できるようにするための“端折り”目的の機構です。ただその位置づけや意味は、その処理系が拠り所とするオブジェクト指向が「何を重要視するか」により様々です。たとえば、古くからのMacユーザーにはお馴染みのHyperCard(HyperTalk)ではイベントの伝達系路、あるいは「委譲」の意味を持たせていたり、C++の流れを汲む静的型チェックを行なう言語では多態性を実現するための「派生型(サブタイプ)」定義に欠かせない機構であったりします。

    人によっては「定義など存在しない」とまで言い切る“オブジェクト指向”ですが、私が調べたところでは、そのオリジンはかなりはっきりしていて、ほぼ2つに絞ることができます。ひとつは、アラン・ケイが最初に「オブジェクト指向」という言葉を作ったときに想定していた意味合いで、「メッセージ指向」【註1】と呼ぶべき考え方です。もうひとつは、C++の設計者であるビアルネ・ストラウストラップが1980年代半ば頃までにまとめた「継承によるプログラミング」と称されるものです。

    ケイのメッセージ指向は、簡単には、「パーソナル・コンピューティングに関わるすべてを“オブジェクト”とそれへの“メッセージ送信”で表現すべし」というドグマにより成り立たせようとする世界観で、哲学的には、ライプニッツのモナド論に通じるところがあります。また生物学的には、すべてが細胞(あるいは機能性タンパク質)で成り立ち、その間でのシグナル授受で営まれる多細胞生物の活動の様子をヒントに、それをシステムソフトウエアへ応用したものとも言われています。Smalltalkは、この「メッセージ指向」を1970年当時の技術で実践し、その有効性を実証するために作られたシステムだと考えることもできます。

    他方で、ストラウストラップの考え方は「メッセージ指向」とはまったく別の独自のアプローチで、C++の仕様策定と実装を通じて整理されました。これは、ユーザー定義型による抽象化手法(抽象データ型)に、継承と仮想関数の動的結合を組み合わせたもので、オブジェクト指向の定番三要素である「カプセル化(抽象データ型、情報隠蔽とも)」「継承」「多態性(多相性、動的結合とも)」の元になった考え方です。ポイントは、SIMULAという言語で初めて言語機能として備えられた「クラス」【註2】を、ユーザー定義型、つまり抽象データ型に見立て、その継承機構を型の派生(サブタイピング)に流用するところにあります。クラス中心の考え方なので、個人的には簡単のため「クラス指向」と呼ぶことにしています。

    「オブジェクト指向」の名の下に、両者は渾然一体として語られがちで、それゆえにオブジェクト指向という考え方は非常に分かりにくいものになってしまっていることは、皆さん、すでにご存じのとおりです。長い歴史の中で繰り返されてきたオブジェクト指向言語間論争のようなものも、根は両者の混同にあると言って過言ではないでしょう。たとえば“純粋なオブジェクト指向”では「すべてがオブジェクトでなければならない」からC++やJavaはてんで駄目だ…とか、Smalltalkで既存のクラスのソースが公開されていたり、それを動的に変更できるのはオブジェクト指向の原則である“情報隠蔽”に反する…などといった類はその典型です。クラス指向において、ユーザー定義型が基本型と区別なく扱えるようになっているべきではありますが、すべてがユーザー定義型である必要はありません。また、オブジェクトそれ自体よりメッセージングのほうに重きを置くメッセージ指向においては、C++などのクラス指向で言うところの「データ型としての完全さ、安全性」にはあまり力は注がれてはいません。

    継承についても同じようなことが言えます。データ型というものを拠り所として物事の抽象化を行なおうとするクラス指向においては、派生型を作るために使われる継承機構というものはたいへん重要な役割を担っています。仮想関数(派生型により再定義されることが期待されるメンバー関数)による動的結合、つまり“多態性”も、継承機構あっての話です。もっとも、クラスとその継承機構を、データ型とその派生に流用することには、理屈の上では問題があることがウィリアム・クック【註3】によって証明されていたり、現場でも継承はトラブルを起こしがちであることが分かってきているなど、クラス指向の屋台骨である継承の地位は現在、急速下降気味だったりもしますが、それはまた別のお話。

    一方で、メッセージ指向を拠り所とするSmalltalkにおいて継承は、クラス指向をあえて意識しないかぎり【註4】、冒頭で述べたように、既存のリソースの再利用のために用意された便利な機構に過ぎません。たとえば静的型チェックを行なわないSmalltalkにおいては多態性も、継承を用いずとも実現可能です。さらには、継承が引き起こす型安全性を壊す深刻な問題などともまったくの無縁でいられます。そんなわけで、継承については当面「使えるときに好きに使う」程度のものと考えておけばよさそうです。

    Smalltalkでは、既存のクラスを継承して生じるクラスのことを「サブクラス」と言い、相対的に、継承の元となるクラスを「スーパークラス」と呼びます。引き続き、BankAccountのサブクラスとしてStockAccountを定義し、株式口座オブジェクトを作ってみましょう。

    註1:ケイらは、1970年代前半までは実際に、彼らの“オブジェクト指向”を意味する局面で「メッセージ指向」という言葉を使っていました。

    註2:「クラス」と「オブジェクト」は、シミュレーション用言語であったSIMULA-Iにおいて「アクション」と「プロセス」と呼ばれていた言語機能を、汎用言語のSIMULA-67(のちにSIMULA)にバージョンアップする際に言い換えたのがその始まりです。「疑似並列処理」のための機構でした。このSIMULAの「クラス」and/or「オブジェクト」という言語機能をヒントにして、抽象データ型(ユーザー定義型による抽象化手法)に加え、クラス指向やメッセージ指向などのオブジェクト指向といった新しいパラダイムが生まれたわけです。

    註3:継承とサブタイピングの関係の研究に詳しいウィリアム・クックは、AppleScriptの主要開発メンバーとして、実は、我々Macユーザーと大変関係の深い人物でもあります。

    註4:Smalltalkでも、制限付きながらクラス指向を実践することは可能です。むしろ、メッセージ指向と衝突したり矛盾しない範囲であれば、クラス指向のエッセンスを汲んだ設計が強く推奨されるのが普通です。

    バックナンバー:
    http://squab.no-ip.com:8080/mosaren/

    藤本裕之のプログラミング夜話 #58

     承前、カッコの話である。前回はカッコが多くなるとプログラムが見にくいという意見に対して、それはカッコの書き方が悪いだけでありチットもカッコのせいではない、という話をした。今回はもそっと話を掘り下げて、そもそもカッコとはなんであるかという哲学的考察からコトをはじめたい。

    おっと本稿読者中にまさか、なんで数学ならまだしも哲学なのだ、あほかコイツはなどとウソぶく浅学非才の徒はおられぬと思うが、一応解説をしておくと数学だの論理学だの天文学だのという学問がそういう風に分類されたのは高等教育というものの方法が確立した近代以降の話であって、かのピュタゴラスは自分を「数学者」だなんてこれっぽっちも思っていなかったし、ゼロを発見した名もなきインド人に至ってはおそらくは「学者」とさえ自称していなかったに違いないのだ。
     そしてオレがこれからここで解説を試みようとしている内容は、それこそゼロの発見ほどまで古くはなかろうがピュタゴラスにとっては既に自明のことであったに違いないことがら。つまりこれら全ての考察が「真理の探求(philosophia)」と呼ばれていたことのコトであるので、その日本語訳……ちなみに翻訳は西周(にし・あまね)先生である、を採って「哲学的」と申し上げているものである。

     余談おわり。再度問う。そもそもカッコとはなんであるか。
     「ゆとり教育」とかが始まってとにかく日本の子供は日の丸見上げて元気に君が代歌っていればいいんだ、となる以前の小学校の算数では、このカッコを四則演算の優先順位を自在に変動させるものとして初めて習う。すなわち「4 + 5 x 6」の答えと「( 4 + 5 ) x 6」の答えは違うというヤツである。覚えがあるでしょ?
     そのせいか、書式は多々あれど同様に四則演算を行なうプログラミング言語の理解においてもカッコをそのようにしか認識していないヒトが少なからずいらっしゃる。が、カッコによって演算の優先順位が変わるのはカッコを使用した結果であってカッコ使用の目的ではないのだ。ここをハキ違えるとカッコの本質を見失ってしまう。
     再度、今度はもそっと一般化してカッコなしとカッコありの2つの式を並べてみよう(Cなど多くのプログラミング言語で使う乗算演算子は「*」だが、ここでは算数に戻って考えていただくべく「x」を使っている。「x」は文字の「エックス」ではないので揚げ足取りはしないでいただきたい)。

     a + b x c ——- (1)
     ( a + b ) x c —- (2)
     ( a + b x c ) —- (3)

     (2)の式におけるカッコの意味を「カッコが無い場合の優先順位を変更し、cとの乗算より先に a と b の加算を行なう」と考えるヒトにとって、(3) の式で使われているカッコは何の意味も無いただの飾りである。まぁ小学生の算数ではその理解でも問題はないが、中学生になって代数が入って来るとモノの本質がおぼろげに見えて来る。

     a + 1 ————- (4)
     2( a + 1 ) ——— (5)
     3( a + 1 ) ——— (6)

     勘の鋭いヒトはもうお気づきだろうが、(4) の式は実はこうも書ける。

     1( a + 1 ) ——— (4′)

     整数 1 との乗算はその対象を変化させないから、我々は特例として (4′)を(4)と書いている。または整数 1 以外との乗算はその対象を変化させてしまうので、我々はそれを正しく表現するために (5) あるいは (6) のようにカッコを使っている、と言っても同じことだが、正規化すれば (4′) こそがこの式の基本形であり(4) の方が便宜型だと言って多くのプログラマ諸氏に納得していただけるのではないかと思う。

    もう紙幅がないので今回は結論として、カッコの正確な意味だけ書いてここで終える。カッコとはとりもなおさず「その内包する部分をその外側から隔離して評価するという意味の表現」である。 小学生が「カッコの中を先に計算しなさい」と教わるのは、そうしないとその外側の値に内側が干渉されることになるからなのだ。そして次回以降に観るように、これは我々が禄を食むところのプログラミングにおいて必要不可欠の重大な概念なのである。では以下次回。
    (2004_11_30)

    高橋真人の「プログラミング指南」第57回

    UNIXとしてのMac OS X

    〜Perlについて(3)〜

     こんにちは、高橋真人です。
     前回の最後に示したPerlスクリプトを実行されてみたでしょうか?

    print A..Z;

     出力結果は、

    ABCDEFGHIJKLMNOPQRSTUVWXYZ

    となります。
     これは、Cで書いたところの

    for (i = 'A'; i <= 'Z'; ++i) {
        putchar(i);
    }

    というコードと同じ結果を出力するわけですが、Perlのprintという関数は、引数にリストを取ることになっています。
     今、「引数にリストを取る」と言ったのですが、こういう状態のことをPerlでは「リストコンテキスト」と言うことがあります。そして、この考え方から「printはリスト演算子である」と言い、printという関数を何と演算子として扱うこともあるのです。
     何しろPerlでは関数と演算子の区別がかなりあいまいでして、つまるところ引数をカッコで囲った場合には関数と呼び、囲まない場合には演算子と呼ぶ、というちょっとビックリな決まりになっています。
     Perlのこういう柔軟というか、いい加減というか、慣れないとかなり違和感のある考え方は、逆に慣れると表現力を広げるための助けとなることも事実です。
     ところで、「リスト」という言葉を使いましたが、リストとはPerlではどんなものなのでしょう。
     リストの説明をする前にまず、Perlにおける変数のお話をしたいと思います。Perlでは主な変数の型として、スカラー変数、配列変数、ハッシュ変数というものがありますが、使用頻度の高い最初の二つに関してとりあえず取り上げてみます。
     スカラー変数というのはCでいうところの変数とほぼ同じような感じのものですが、基本的には何でも入ります。具体例を示せば、

    $string = 'Hello world';
    $number = 256;

    というように文字列でも数字でも入るのです。ただ、スカラー変数である限り、必ず頭に$を付けなければならないということになっております。
     一方、配列変数はCで言う配列と同じように複数の値を保持できる仕組みですが、スカラー変数と同様、基本的に何でも格納できますので、一つの配列の中に数値や文字列が混在することも可能です。具体的には、

    @array = ('Hello', 256, 'world');

    というような感じで、配列変数に値を格納する場合に、複数の値を同時に与える時には、それぞれの値をカンマで区切った上でカッコでかこんでやります。配列変数の場合は、必ず頭に@を付けなければなりません。
     やっかいなのは、配列の特定の要素に個別に値を設定するケースです。たとえば、上記の@arrayという配列変数の2番目の要素を128に変更するとしましょう。この場合、コードは

    $array[1] = 128;

    となります。
     初めてPerlに触れる人がほとんどと言ってよいほどつまずくのがこの部分で、「@arrayというのが変数の名前なのだから、頭は@じゃないのか?」と疑問に思うのですが、配列の各要素はそれぞれがスカラー変数になるので、$でなければならないというのがPerlのルールなのです。ちなみに、@arrayという配列変数があったばあい、$arrayというスカラー変数を作ることは可能で、さらにこの二つの変数は完全に別のものであるということになります。
     こういった、Perlに独特の文法規則が入門者への敷居を高くしていることは事実でしょうが、慣れてくるとかえって便利に思えてきます。
     さて、話をリストに戻しましょう。上記の配列に値を代入する例で、値をカンマで区切ったものをカッコで囲んだ例が出てきましたが、実はこれがリストです。配列も、多くの場合リストのように振る舞うため、リストと配列の区別が付きにくいのですが、リストと配列はPerlにおいては明らかに別のものです。実際、両者の違いが出てくる状況はあまり多くはないため、最初のうちはなかなかこの辺の区分けのできない方も多いようです。
     そんなわけで次回は、このリストと配列の違いという点についてさらに解説してみたいと思います。

    ニュース・解説

    今週の解説担当:小池邦人

    Carbon ドキュメント & サンプル & SDK ナビゲーション(2004/12/03)

    【開発環境】

    各方面からの話をまとめてみますと、Apple社がNewGWorld()やCopyBits()を含むすべてのQuickDraw APIを抹殺しようと考えているのは明らかです(笑)。もう少し具体的に言えば、CGrafPortに依存するAPIをすべて消し去り(代用APIを用意する)、描画に関してはCoreGraphics(Quartz 2D)のCGContextRef環境のみを許するということです。そのうちOpenGLの描画環境も統合するかもしれません。まあ、すぐさまAPIそのものを消してしまうと動かなくなるCarbonアプリケーションが続出しますので(笑)、そんなに早急には断行できないでしょうが、将来的には開発環境がらみでAPIの使用をロックするかもしれません? つまり、XcodeではCMFアプリケーションが開発できないようになっているのと同じ状況になるわけです。

    QuickDraw APIはスレッドセーフでもありませんし、GPUの能力も生かしていません。仕様自体も古く、現状のMac OS Xシステムにはマッチしなくなってきています。逆に、それを使用することが処理のボトルネックになっているケースもあるわけです。Apple社側でもその点を重視しており、「Transitioning to Quartz 2D」といったドキュメントを提供し、描画処理をCoreGraphicsへ移行するようにと説いています。そのドキュメントを参考にし、QuickDraw 関連のAPIをすべて除外しても、現状の自作アプリケーションの開発が継続できるかどうかを詳しく調べてみました。各Managerのヘッダファイルを参照すると、QuickDraw依存 API(例えばRegionとかPictureを使うもの)は随分と新しい物に置き換えられていることが分かりました(もしくは仕様の拡張で対応している)。

    ただし完全に準備万端かと言うと、そうでもないのが現状でして(涙)、Mac OS X 10.4(Tiger)においてより完璧になるよう努力中と言ったところでしょうか? 個人的な要望としては、CoreGraphics APIにはメモリ内のビット操作やメモリ移動に関わるAPIがないので、それらを新規に追加してもらいたいと思います。例えば、CopyBits()における部分的な画像(メモリ)転送や、CopyMask()とRegionによるマスク処理などは画像描画のみに利用されているわけではありません、オフスクリーン間での特殊なメモリ操作にも頻繁に活用されているのです。こちらの方面はTigerのCore Imageが受け持つことになるのかもしれませんが(なのか?)、QuickDraw依存度の大きいQuickTimeも含め、QuickDrawとCGrafPortが完全に消滅したとしても、Carbonアプリケーションの開発者がまったく困らないような完璧な準備をお願いしたいと思います。

    【テクニカルドキュメント】

    前回から12月3日の期間中、Apple社のDocumentationサイトにはドキュメントが17登録されました。WebObject関連のドキュメントも6つあります。このうち新規のドキュメントは「Pasteboard Manager Programming Guide」のみです。Pasteboard ManagerはCarbon FrameworkのScrap Managerに取って代わるAPI群であり、Clipboardを用いたCopy&Paste処理に最新の仕組みを提供します。ちなみに、Pasteboard ManagerはMac OS X 10.3以降でしか利用できませんので、アプリケーションに実装する場合には注意してください。前回紹介した「Pasteboard Manager Reference」と同時に参照すると良いでしょう。残りのうち「Component Manager for QuickTime」の内容はかなり変更されていますが、それ以外のドキュメントはマイナーな変更のみです。

    「Apple Human Interface Guideline」(PDFあり)
    「Cocoa Bindings Reference」
    「Component Manager for QuickTime」(PDFあり)(改編)
    「Core Foundation Reference」
    「Deploying Applications」(PDFあり)
    「Enterprise Objects」(PDFあり)
    「Initializing QuickTime」(PDFあり)
    「Kernel Programming」(PDFあり)
    「Low-Level File Management」
    「Outline Views」
    「Pasteboard Manager Programming Guide」(PDFあり)(初版)
    「QuickTime Overview」(PDFあり)
    「Web Kit C Referenc」(PDFあり)
    「WebObjects 5.2.3 API Reference」
    「WebObjects Dynamic Elements Reference」(PDFあり)
    「WebObjects Extensions Reference」(PDFあり)
    「XML Serialization」(PDFあり)

    http://developer.apple.com/documentation/index-rev-date.html

    前回から12月3日の期間中、新規のテクニカルノートはひとつも登録されませんでしたが、新しいテクニカルQ&Aは2つ登録されました。「SetSoundMediaBalance balance parameter clarification」は内容の改訂です(日本語訳もあり)。「My custom item dismisses my Navigation Services dialog」の方は、Mac OS X 10.2におけるNavigation Serviceのバグの回避方法について解説されています。

    QTMTB49「SetSoundMediaBalance balance parameter clarification」
    QA1381「My custom item dismisses my Navigation Services dialog」

    http://developer.apple.com/technicalqas/index-rev-date.html

    【サンプルソースコード】

    前回から12月3日の期間中、Apple社のSample Codeサイトには、新しいサンプルソースコードがひとつだけ登録されました。OpenGLを用いた描画でのテクスチャの活用を紹介したCocoaサンプルです。

    「NSGLImage」(Cocoa&OpenGL関連)

    http://developer.apple.com/samplecode/index-rev-date.html

    【デベロップメント SDK】

    前回から12月3日の期間中、Apple社のSDKサイトには新しいSDKはひとつも登録されませんでした。

    http://developer.apple.com/sdk/

    MOSAからのお知らせと編集後記は割愛します

    MOSA Developer News   略称[MOSADeN=モサ伝]
    記事投稿受付 http://www.mosa.gr.jp/topics/mdn-toukou.html
    Apple、Mac OSは米国アップルコンピュータ社の登録商標です。またそのほかの各製品名等はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    特定非営利活動法人MOSA  http://www.mosa.gr.jp/
    Copyright (C)2004-2006 MOSA. All rights reserved.