iPhone前とiPhone後、かつiPhone以外の「後」を考察する

常々「Windows Phoneには電話機能はいらない、WiFi に特化して軽量/バッテリーの持ちを考えて win アプリが導入できれば即売れる」と話したりしているのですが、サムスンと apple の訴訟で提示した apple がそれを示しているという意味で、

iPhone前とiPhone後・・・ | Blog!NOBON
http://blog.nobon.boo.jp/?eid=904179

私の場合、はじめての apple 製品が ipod で、その後が初代 iPad という、iPhone を無視した経緯があるので、かつての iPhone がどれほどいまいちだったのかは分かりませんが…少なくとも、iPhone の形状(全面に静電式タッチディスプレイ)という方式を貫いて、おらくそのまま消え去るであろう(十年後位にはなると思うのですが)というスタイルは、iPhone というスマートフォンの形状は「誕生と同時に完成形」であり「それ以上は進化しない」という特徴をもっています。

実は、使ってみると分かるのですが、

  • 電話としては非常に使いにくいです。
  • 従来のボタン式のゲームは使いづらいです。
  • 電子書籍を読むには画面が小さすぎます。

という不便さはありますが、それを上回るほどの

  • メモ帳などのアプリが、簡単に app store から入れられます。
  • タッチタイプのスマートフォン型のゲームがたくさんあります。
  • 書籍は「読む」のではなく「ブラウジング(流し読み)」します。
  • ツイッターやフェイスブックが何処でも使えます。
  • Apple というブランド性

という利便性(あるいは中毒性)があります。
私の場合、2年前にツイッターにハマった直後、iPhone に買い替え(実は、飛行機の中で携帯電話を落としてしまったので、やむなく iPhone 4 に買い替え。iPad は既に持っていた)という経緯もあるのです。携帯電話でツイッターをやるよりは、iPhone でツイッターを閲覧する方が確実に便利です。これはタッチタイプというペンがいらない方式かつ、ブラウジングではなく専用アプリによる動作のなめらかさが長所になるのですが、ボタン動作に関しては、docomo の java アプリで作れば同等の操作性を実現できるので(ボタンを押すという、従来?方式でもありますが)特に iPhone が良いという訳でもありません。

しかし、市場原理として(あるいは経営的な判断として)、「最初に売れているものを追う」というサムスン方式は、かつて日本の電機会社が行った手法でもあり、現在でも行われている経済的な手法(ランチェスターの法則)、あたり前の方法です。既に「高速道路」が引かれているわけですから、それを使って追えばいいわけです。
なので、サムスンが apple の市場を喰い、あるいはスマートフォンという市場を拡げてパイを apple と分割する、かつ apple がスマートフォンという市場(apple にとって、スマートフォンという市場は、iPhone 専用の市場です)を荒らされるあるいは市場が無法化するのを嫌って、サムスンを訴えるのも当然なことです。

まあ、そんな泥臭い経営的な判断はさておき、apple とサムスンがお互いに体力を消耗している間、私達は何をすれば良いでしょうか?ってことです。

■ガラケーの末路と将来性

日本のガラケー(フューチャーフォン)が iPhone に一掃されつつあるように見えますが、他国の多機能電話も一掃されつつあります。OS 的に、iOS, Android が席巻してくると symbian とか brew とか docomo の java とか、panasoinc の 独自 itron が一掃されつつあり、欧州の gms 系なんて何処いったんでしょう、っていう状態です。フィンランドの経済(福祉社会)を支えていた nokia が凋落すると国も危ういという現象は、サムスンが凋落すると韓国が危ういという状態と同じだったりします。まあ、サムスンの重役が国策に関与しているという点では、初期の原子力発電所建設に経済界が強くかかわっていた(今でも関わっている)という点と同じですね…まあ、それはともかく。

ワタクシとしては、スマートフォンの電話機能には辟易していて、それほど電話が掛けない私であっても時々普通の携帯電話が恋しくなります。これは、iPhone であれ、sumsong の galaxy であれ同じことです。その他の android 型スマートフォンも同じ。元々、電話機は「受話器」と本体の電送部分が分かれていて「受話器」には、聞く部分と話す部分が別々に「顔の形状」に合わせて作られていました。これは、現状のスマートフォンでは完全に無視されています。平たい液晶だから、という点もありますが、従来の携帯電話では、音声を聞くところと話すところがある程度マッチングするように作られています。折り畳み携帯の場合は液晶を守るという役目もありますが、ある程度曲がることができるので、マイクの位置を変更しやすいという利点があります。

が、この電話機能としてのデザインが無視されているのは、スマートフォンがそもそも電話としての機能を優先させていないという第一の理由があります。Apple としては、iPhone で電話をされたって一銭(1セント)も入ってきません。そこで思いついたのが、app store という方式です。これは mac os 自体にもかつてあった?のかどうか調べていないのですが、自社の store で直接「買わせる」ことによってマージンを取れるようにします。商品自体は、apple でも作りますが他の品ぞろえも多くしておきます。いわゆる「流通業」に参入した訳です。
実は、流通に関しては docomo も au もやってはいたのですが、いまいち盲点/乗り気ではないような気がしますね。アプリを作るために docomo の java を公開したものの、公式や野良アプリが混在してしまって「流通業」には参入していません。docomo の場合は、アプリ販売からのマージンよりも、電話することよる課金が多いので、そちらに流れていたという現状もあります。今後の docomo の戦略としても「電話を掛けさせる、データを流れさせる」という方向になるはずです。

まあ、そんな会社の思惑とは別に、スマートフォンではない携帯、主に電話機能に特化かつ iPad などのタブレットとうまく融合するものを考えてみると、

  • 黒井白子が使っていた細長いペンシル型の携帯電話でもOK
  • au が出していた骨伝導を利用したイアフォン型の電話機のミニ版でもOK

な具合にタッチタイプの液晶部分を外してしまいます。iPod nano がミニサイズして行ったと同じように「電話機能」のデザインを重視して、それだけを残して他を排除します。

  • タブレットPC、WiFi専用スマートフォン?、に Wifi 機能を提供するディザリング機能(ルータ機能)

確かにタブレットPCに3GSなどの通信機能が付いていれば、便利には違いないのですが、「定期的な」通信料が掛かりすぎます。ユーザーにとっては、携帯電話のみに通信機能があって、それ以外は wifi/無線lan/bluetooth で ok です。現在のように機能が重なってしまった、スマートフォンと携帯電話を2台持つぐらいならば、

  • ルータ機能付きのミニ携帯電話
  • 大きな画面を持つ軽いタブレットPC

の組み合わせのほうが良いでしょう。あるいは、ジャックを付けて、タブレットPC に従来式のモデム機能を提供してもよいのです。

ただし、これは docomo のような回線を持っている会社は売り出しませんし、Apple や sumsong のように既にスマートフォンを持っている会社は出さないでしょう。なので、活路としては、windows phone なんですけどね…という訳で、最初の「windows phone に phone 機能を外せば」に戻るのです。

■タブレットPC の将来

私は、iPhone とは別に wifi-pockcet を持っています。wifi のみの ipad, ノートPC を活用するためには、やっぱり無線LAN 専用の機器があったほうがよいのです。また、何人か集まったときには無線LANの貸し出しもできるので、営業的にスムースです。

さて、電子書籍とタブレットPCという二つの市場がありますが、重量の問題が解決されれば、この市場はもうちょっとスタイルが変わってきます。

  • ほぼ使い捨てにできる、軽量な e-ink な電子書籍
  • ゲームアプリを導入が簡単なタブレットPC

という二分割ですね。どちらも、重量は200g程度が望ましいのですが、普通の文庫本や漫画本の代用にするならば、電子書籍は 180g よりも軽くしてほしいが、ゲーム中心となるタブレットPC は、PSP 程度(280g)程度で良いのです。e-ink の場合はダウンロードと画面の切り替え時以外、電気を喰わないのでバッテリー容積を少なくすることと、先の通信機能を wifi 化してしまうことにより更に軽量化あるいは「使い捨て」化が可能です。使い捨てにしなくても「リサイクル」化ができれば ok です。
「使い捨て」の e-ink を希望するのは、落として壊してしまって惜しくない価格帯であってほしいのです。プレゼント的に配布できるとか、
街中で100冊位の入れ込みで売れるとか、そういう従来の「本」感覚で売れる/読める感覚が欲しいのです。

amazon や kobo 社(楽天ではないよ)、はこのあたりを目指してほしいですよね。通信機能なんかは街の本屋さんで wifi 購入でもよいので、3gs の機能は不要なんですよ、本来は。

タブレットPC の場合は、ノートパソコンに代用するパターンとゲーム機に代用のパターンがあります。ノートパソコンの代用のパターンは、microsoft の surface のようにキーボードを別に用意します。iPad でもそうなのですが、ソフトウェアキーボードを出して執筆というのはほぼ難しいです。入力が面倒だから結局ノートパソコンを持ち歩いてしまいます。
しかし、ゲーム機の代用(あるいは後継)であったり、業務用のタブレットPCの後継(コンビニで使っている商品照会だとか、デパートでおいてある商品紹介の iPad だとか)はかなり様相が違います。

ペンタッチ式の業務アプリは windows xp のタブレット時代からあり、今も使われています。ちなみに、居酒屋のチェーン店では palm os がまだ使われていますよね。ペンタッチはそれなりに便利なのと、一度業務で作る/使うとなかなか次の段階には進みづらいのが、業界用アプリの特色です。
なので、タブレット市場にいくつかのセグメントがあるのです。

  • ゲーム機の後継/代替としてのタブレットPC
  • ノートパソコンの代替としてのタブレットPC
  • 業務タブレットの後継としてのタブレットPC

先に書いた通り、実はノートパソコンの大体にタブレットPCは難しいのです、確かにソフトウェアキーボードで打てないこともないのですが、タブレットの画面を半分以上覆ってしまうのは、ちょっと文章が見えなくて書ききれません。こうなると専用のキーボードが欲しいところで、そうなると単なるタブレット機能がある画面になってしまいます(それでも使い方はいろいろなんですが)。

ゲーム機の後継としては、iPad も microsoft の sufrace も同じです。iPad の場合は OpenGL で画面を作ることになりますが、windows 8 の場合は directX ですね。このあたりの「作り易さ/作り難さ」はよくわかりません。デバッガ関係では、directX のほうが圧勝な気がするのですが。ここは、psp などの専用機も交えないと駄目ですからね。

ですが、私の本来の狙い所は「業務タブレットの後継」です。実は、この分野を見ていくとレガシーなものをレガシーなままに使っているところもあり、新規技術を導入しているところもあり(顔認証とか)と様々です。レガシーなところは、windows xp タブレットの便利さです。vb6 がそのまま動くために、かつての vb6 アプリをタブレットPC でも動かせば、そのまま使えてしまうという利点があります。全画面で作ってしまえば、vb6 であろうと、.net であろうと変わりませんからね。画面操作のコンポーネントは旧文化オリエントのものを使ったりする訳です。

一方、新規技術のほうは、タブレット機能を使いたいがために、現在ではちょっと複雑になってしまっています。当時、液晶のタッチパネルが高かったので効果的に配置ができなかったのですが、安価なタッチタイプのタブレットPCが出てくれば、自動アプリ配信、リモートセッティングなどがやり易くなります。バックグラウンドに大きなPCを隠す必要もない(大抵は柱に隠してあります)。タッチタイプの液晶が壊れれば、機器ごと変えることもできるし、無線LAN が標準で付いているので有線LANケーブルの設定も必要ありません。これはかなりメンテナンスフリーな配置ができるわけです。

そんな訳で、私としは、

  • 単機能かつミニサイズの携帯電話(ルータ機能あり)
  • 使い捨てに近い軽量 e-ink タブレット
  • wifi 機能のみの軽量タブレットPC

を強く望むし将来的にはそうありたいなと。まぁ、通信市場としての docomo, au、スマートフォン市場としての apple, sumsong の攻防/思惑があるわけですんなりとはいかないでしょうが、なんども言いますが、windows phone に phone 機能が無ければ買うのにッ!!!

カテゴリー: 雑談 | iPhone前とiPhone後、かつiPhone以外の「後」を考察する はコメントを受け付けていません

[C#] 型推論と暗黙のキャスト(implicit)を組み合わせる

Microsoft、「Metroスタイル」改称へ――米メディア報道 – ITmedia ニュース
http://www.itmedia.co.jp/news/articles/1208/03/news053.html

Metro Style という用語が消えるそうだけど「メトロスタイル」の可能性が低くなるのであれば、それはそれで歓迎かと。某メトロ本を書く前の文章練習として、少し書きつけます。

C# の var は、型推論という形で C# の型をコンパイラが判定するという機能で、宣言部のコードが短くなるということと、LINQ のクエリを受けるときに小難しい…というか記述不可能な書き方をしなくてよいのが大きな利点です。

CPoint pt = new CPoint();

のかわりに

var pt = new CPoint();

と書くわけです。これ、VB で書くと、

Dim pt As New CPoint()

なので、宣言部だけだとあまり意味がないのですが、

var query = from t in Table where t.name = “masuda” select t ;

のように LINQ のクエリを受ける場合は「ほぼ必須」ですよね。「ほぼ」っていうのは、IEmutable か IQuerable を使えばなんとか可能なのですが、インテリセンスの助けがないと確実に無理ッ!!! 素のテキストエディタを使う場合は「var」が必須になります。

C# は C++ の型の書き方を継承しているので、宣言をするときに、あたかも型を2つ書かないといけないという不便さが際立つのですが(VB だと1回だけでいいですよね)、もともと C++ の場合は、

CPoint pt ;

CPoint *pt = new CPoint();

といった異なる書き方をするので、必ずしも型が重複しているという訳ではありません。先のほうは内部変数でスコープを抜ける時にデストラクタが呼ばれる(自動的に解放される)ので、普通は上記の書き方を多用します。C# の場合は、using を使って

using ( CPoint pt = new CPoint() ) { … }

のようにスコープを決めることもできるのですが、なんかいまいちです。コーディングの経済性からいえばタイピングの少ない方に流れがちなので、私の場合は using はあまり使っていません。明示的に画像関係(Bitmapなど)を扱う時ぐらいです。

■暗黙のキャスト(implicit)

型推論と反対の発想(と私は思っている)ものに、暗黙のキャストがあります。型推論は、コンパイラが構文(関数の戻り値や別の型)から一意の型を決めますが、キャストはコードを書いている人=プログラマが型を決定します。余談ですが、F# の場合は型を推論すると同時に、’a という anonymous な型が用意されています。これはテンプレート/generic の T と同じように働くのですが、表面上は型がその場所で規定されているのか、呼び出し側で既定されているのかを区別しません。C++ や C# の場合は CPoint() のように「<>」を使って「不定の型」であることを示すところが大きな違いと感じています。ちなみに、VB の場合は「CPoint(Of Integer)()」となって実に奇妙な感じなのです。

LINQ や XML を扱っていると、ツリー構造なりテーブル構造が単数と複数の組み合わせであることがわかってきます。LINQ は、プログラムコードの中から for/while 文を排除していく故に複数行のコードがワンライナーで記述できる(数式に近くなる)という利点があるのですが、単数と複数の要素を暗黙のキャストを使って使い分けると、.FirstOrDefault や [0] とか != null を減らすことができます。

一例を示すと HtmlDom では、HTML タグに関して、HtmlElement という単数の要素と、HtmlElementCollection という複数の要素≒リストを用意しています。

class HtmlElementCollection : List<HtmlElement> { … }

ツリー構造なので、HtmlElement は、子要素として HtmlElementCollection Children というプロパティを持っています。

さて、とある要素に div という子要素があるかどうかを調べるのには、LINQ を使うと次のように書けるように作ります。

# @neuecc さんより
# LINQ to random thoughts – NyaRuRuの日記
# http://d.hatena.ne.jp/NyaRuRu/20080205/p1
# Any を使えという指摘が。そりゃそうだ。 Count すると全件検索してしまうがな orz

if ( root.Children.Any( n => n.TagName == “div” ) ) {

要素があるかどうかを Anyメソッドで調べるのですが、大抵の場合は「子要素があれば最初の要素がほしい」というのが普通です。そうなると、.First メソッドを使って、

var el = root.Children.First( n => n.TagName == “div” );

ってことになるのですが、子要素がない場合は、el の値は null になってしまいます。こうなると != null が必要になってちょっと面倒です。なので、.FirstOrDefault というメソッドを使って次のように書き換えます。

var el = root.Children.FirstOrDefault( n => n.TagName == “div” );

さて、ここで div は最初のひとつだけということにしてましたが、最後のひとつを取りたい時はどうするのでしょうか? うまい具合に Last メソッドや LastOrDefault メソッドがあるのでこれを活用します…ってことにヘルプ的にはなるのですが、こうやっていくと組み合わせ的にメソッド数が増えてしまいます。

ならば、

var el = root.Children.Where( n => n.TagName == “div” ).First() ;

のようにどうせ LINQ は遅延評価なのだから、Where で検索した後に First だけを持ってくるのが素直では?と思ってしまうわけです。まあ、実際にこういう書き方もできるわけで。そこで、暗黙のキャストを使って、First 自体も消してしまおうというのが、HtmlDom の発想(元ネタは ExDoc)です。

HtmlElement el = root.Children.Where( n => n.TagName == “div” ); // 最初の要素を取得

HtmlElementCollection els = root.Children.Where( n => n.TagName == “div” ); // 複数の要素を取得

のように、あえて「型」を記述させて「最初の要素(単数の要素)」なのか「リスト(複数の要素)」なのかをプログラマが決めます。Where メソッド自体はリストを返すのですが、HtmlElementCollection から HtmlElement への自動的なキャストを許すことで、こんな書き方ができます。

public class HtmlElementCollection :  List<HtmlElement>
{
    public static implicit operator HtmlElement(HtmlElementCollection col)
    {
        if (col.Count > 0)
        {
            return col[0];
        }
        else
        {
            return HtmlElement.EmptyElement;
        }
    }

遅延実行ではありませんが、上記の形で簡単に暗黙のキャストが実装できます。HtmlElementCollection から HtmlElement にキャストした時に、要素があれば先頭の要素を、要素がなければ EmptyElement という空の要素を返します。これは、.FirstOrDefault というメソッドと同じ動作をします。空であるかどうかは、null と比較するのではなく、IsEmpty というプロパティを使うわけです。

こうすることで、先の el という変数は null になりません。null にはならないので、el.IsEmpty や、el.Children.Where という書き方を続けてできます。Where メソッドを直列にする書き方は、LINQ でも同じで常に IEmutable というコレクションもどき(コレクションに見えるが、遅延実行されるので、内部的には実行メソッドの順序だけを保持しているという点で「もどき」)を使うことで実現されています。もう少し文法的に煮詰めたら HtmlDom もそうする予定です。

■要素を探すというコードが大半であるという現実

XML や HTML を扱う場合には「指定した id を持つ要素を探す」というコードが頻繁に発生します。ElementById というメソッドで、要素を探して値を取得したり設定したりします。for/while の場合は、2つの動作があって「要素に対して同じ操作を繰り返す」というのと「要素を探し出して、何か操作して終わる」というのが頻繁に発生します。

サンプルを書いて考えてみると、

□複数の要素を一気に更新

foreach ( var el in root.Children ) {
  if ( el.TagName == "div" ) {
    el.Value = "xxx";
  }
}

var q = root.Children.Where( n => n.TagName == "div" );
// LINQ の場合、連続して更新ってどうやるんだっけ?
foreach ( var el in q ) {
  el.Value = "xxx";
}

// HtmlDom の場合
root.Children.Where( n => n.TagName == "div" ).Value = “xxx”;

□ひとつの要素を見つけて更新

foreach ( var el in root.Children ) {
  if ( el.Attribute("id") == "m1" ) {
    el.Value = "xxx";
    break;
  }
}

// LINQ の場合
root.Children.Where( n => n.Attribute("id") == "m1" ).First().Value = "xxx";

// HtmlDom の場合
root.Children.Where( n => n.Attribute("id") == "m1" ).Value = "xxx";

上記のように HtmlDom では使って単数/複数を同じように扱うことができます…と云いますか、LINQ 構文内では、HtmlElementCollection として扱い、同じことが HtmlElement にも適用できる、という「見かけ上」の問題を解決しています。単数のほうは、正確に書くと HtmlElement にキャストすることになるので、

((HtmlElement)root.Children.Where( n => n.Attribute("id") == "m1" )).Value = "xxx";

ということになるのですが、動作としては「id=”m1”」である要素は、「全体の1つしかない」という「仕様」を前提にしてコーディングをするので、複数あるときはイリーガルな訳で無駄なのです。逆に、データの中にひとつもないというのもイリーガルなわけで、これらの処理は正確には「例外」として処理する必要があるのですが、コーディングとしては面倒だし「忘れ」そうですよね。そうそう、この「忘れる/漏れる」というヒューマンエラーを回避するためにも、単数/複数/null を一括して扱う implicit な訳です。安全側に倒れるという安全管理の手法です。データが多少イリーガルでもプログラムは落ちずになんとなく正常に動くというパターンです。

そんな訳で、LINQ の文法である from/where/select を活用して、同時に暗黙のキャストと組み合わせている HtmlDom ですが、公開はもうちょっと先かなぁと。遅延実行の実装がよくわからいのが本音で、もうちょっと LINQ の実装をながめなくては。

neuecc

カテゴリー: C# | 1件のコメント

Raspbarry PI が届いたよ

船便でやっとこさ届いた Raspbarry PI です。

IMG_0370

Raspberry Pi(ラズベリーパイ)
http://jp.rs-online.com/web/generalDisplay.html?id=raspberrypi

いやいや、船便で時間が掛かっているうちに日本でも手に入れるのが楽になってしまいました orz 値段的には、ドルでも円でも同じみたいです。$35 プラス船便代だったので、日本で買ったほうが安いかと。いや、今は品切れなので、それなりには早いのかな?

IMG_0371

電源は、microUSB というちょっと特殊なものなのですが、通常のUSBからの電源供給は上のような100円ショップであるもので使えます(動作確認済み)。2種類あるので、薄い方を買えばOKです。まぁ、間違っても100円なのでよいかと。

私の場合、Raspberry PI の本体よりも、HDMI 出力の方が問題だったりして、液晶モニタが古いタイプだと HDMI のコネクタがなかったりします。Raspberry PI のコネクタは「タイプA」なので、通常のオーディオ用の「タイプA」を買ってきました。

早速、microUSB を普通のPC から繋げて、

  • 無線LANのマウス
  • 有線LANケーブル(raspberry pi は wifi が入っていないので)
  • USB キーボード

を入れると、おなじみの linux のブートログが表示されたのち、

IMG_0372

ログインしてから、startx でデスクトップが表示できます。ここでマウスも使えるのでOK.

IMG_0373

キーボードは、ASCII キーボードしか対応していない(多分、設定を切り替えればOKかと)ので記号が打ちにくいですが、こんな風にブラウザも表示できます。

IMG_0374

GUI はかなりもっさりと動きますが、これはメモリが少ないしGPUのパワー不足かと。そもそもが高機能linuxを目指している訳ではないので、これで十分です。

ディスプレイは要らないので、terminal で入れるようにポートを空けて、telnet で入れるようにすればokかなと。基本はコマンドラインで何かやるので。

シャットダウンは普通にshutdownコマンドを使えばOK。まぁ、microUSB を抜いてしまっても、SDメモリなので壊れる心配は少ないかと。

カテゴリー: 雑談 | Raspbarry PI が届いたよ はコメントを受け付けていません

Visual Studio 2012 の発売は 9/12、Windows 8 は 10/26

Microsoft、「Visual Studio 2012」と「.NET 4.5」の正式版は9月12日と発表 – ITmedia ニュース
http://www.itmedia.co.jp/news/articles/1208/02/news022.html
Windows 8がRTMに 開発者は8月15日から入手可能 – ITmedia ニュース
http://www.itmedia.co.jp/news/articles/1208/02/news019.html
「Windows 8」の発売は10月26日 「Surface for Windows RT」も同日発売 – ITmedia ニュース
http://www.itmedia.co.jp/news/articles/1207/19/news019.html

Windows 8 RTM, Visual Studio 2012 RTM が 8/15 の「敗戦記念日」(米国にしたら戦勝記念日か?)というのはさておき、Winodws 8 本を書くにあたっては、正式版を待っての画面キャプチャとなるので、大まかな画面キャプチャは RTM で済ませていおいて 10/26 を待って画面を確認、というスケジュールですかね? > 某編集さま。

Visual Studio 2012 自体は、Windows 7 にもインストール可能なのですが、今回の書籍のメインターゲットとなる metro style application は Windows 8 での開発のみとなるので(シミュレータが自分へのリモートデスクトップという事実もあるし)、となると Windows 8 + Visual Studio 2012 の組み合わせで画面操作をチェック、ということになりますね。

あわせて、Windows Store への登録準備、と言いますか実験的な登録だけがあるので(例によって、Windows Phone Store への登録はしませんw)、審査が通過するサンプルアプリを作らないといけないという微妙な感じなのですが…まぁ、徐々に準備をしてきましょう > 某勉強会のメンバさま

で、私は RTM の頃は何をしているかというと、、、MFC+Fortran と格闘して、傍らに mac mini だったりする訳ですよ。とほほ?

カテゴリー: 雑談 | Visual Studio 2012 の発売は 9/12、Windows 8 は 10/26 はコメントを受け付けていません

さよならもいわずに

このブログには日常の事を書かないことにしているのだが、本屋で上野顕太郎「さよならもいわずに」を見つけて記録を残しておくのも供養かと思い、1時間ほど書き下してみることにする。

24日に父(享年75歳)が死んだのは、2年前から始まっていた病院生活の終わりであった。7月頭に既に死を覚悟する旨を医者より聞かされ、先行きがないことにより直前の酸素吸入や輸血をしないことを決めたものの、直前に死の前に孫の顔を見せようかと札幌に行った時のことでもあり、1日前に苦しみながら息をする姿に今からでも輸血をすればとも思ったものの、時は遅く、いや実際には輸血をしたところで死が2週間ほど延びるにすぎず、最後は急性肺炎のため息ができなくなり、24日の夕方に臨終ということになる。
孫の顔を見せるという、という名目であるものの、実は2年前の交通事故から意識がなく軸索損傷にて反応も少なく、医者には「反射」と呼ばれるようなモノを追う目をしていた父ではあったが、声を掛けるとこちらを向いたような気もし、誰かが来ると瞼を開けて負うような気もし、硬直しつつある腕や手を拡げようとすると痛がり、顎が割れてしまった口をあくびのために開け閉めするたびに痛い顔をし、意識に関係なく伸びる髭を電動剃刀で剃ろうとすると鼻の下を伸ばし少し剃りやすいように仕向けるような気もし、兎も角も「意識がない状態」が続いていて、全く喋らず、トイレにも立てず、手足も動かせず、少しだけ瞳を動かし、疲れると瞼を下げる動作をする父という状態は、「老いた父」でもなく「呆けてしまった父」でもなく、ただそこに目の前のモノに反応する赤ん坊のような父の姿になったとも言えた。
そのような期間が2年間続いた。仕事場が東京にあるという場所がら、札幌に頻繁に帰ることはままならなかったが、下の子が生まれ、その1か月後に交通事故があり、幼い子を妻に任せて(妻自身の産後という大変な時期であった)2週間ほど北大の病院に母と通い詰めた。
タクシーの中で「ひょっとしたら、即死のほうが良かったかもしれない」と恨み言を言うかもしれないと、弟を怒鳴ってしまったしことは、実は楽観的な事実でしかなく、実際はモノ言わぬ状態だけが残された。
病状は重く、いや、足の骨折と内臓破裂と顎の骨折、あばら骨の骨折と、即死に近いものがあったものの、幸いにして足を切断することもなく、内蔵破裂で大量出血死することもなく深夜の長い手術と救急病棟の1週間があったものの「死」は免れた。しかし、意識は戻らなかった。いや、当時は意識が戻るものと思い、1ヶ月、孫の運動会のテープや声掛け、日に15分の面会を続けたのだが、意識は戻らなかった。
頭をひどく回転させると、脳と体を繋ぐ神経が切れる現象が発生し、脳が孤立状態になる。これが軸索損傷で、外部の世界から完全に遮断されてしまうとのこと。痛みも音も何も感じない世界に置かれ、全く眠った状態と医者には説明を受けたものの、瞼をうっすらと代えてこちらをきょろきょろと見る姿は、何かを探しているような感じがして、意識がないとは思えなかった。いや、脳神経が少しずつ回復する、回復しないにせよ別の回路が代用するという生命力があればこそ、事故直後のうつろな目の動きと、2年後の少しはっきりとした目の動きは、何か見ているような感じがした。手も指も顔も動かすことは叶わなかったが、俗な言葉を使えば「心」は残っていたのであろう。

だから、2年間の危篤状態の末に、最期に急性肺炎で亡くなったという言い方が正しい。意識がない状態では、嚥下もままならず流動食は口の管から、鼻の管から、最後には太腿の血管にそそぐことになった。喉を切開する時も、意識が戻った時に声が出ないのではないかと心配したものの無用であったし、2か月程の指や腕、全身のリハビリや針治療を繰り返したものの結論だけ見れば全ては無用だったと言える。ただ、父にとって死を引き延ばしてしまったのか、最期の自らの体が動かない状態を無用に長く続けさせてしまったのかと疑問に思うこともたびたびあったが、気管切開をして酸素吸入をやめてもなお自力で息をし、生来の健康性から(常備薬はなかった)心臓は強く打ち、切り開いたお腹の傷も治り、骨折した足の骨がついた生命力をみると、なんらかの「意志」があったのだから、意志に沿うだけと思ったものだ。だからこそ、延命処置としかならない輸血は断ることにした。実は2月に輸血を行っている。1回だけは延ばしてあげたいという想いと、後悔なく試しておきたいという思いがあったものの、それから1週間ほどは高熱が続いたそうである。治るのであればそれでよいものの、治らないとなれば、意識がないとすれば「延命」に何の意味があるのかと疑問になったが、それは「私達の時間」を確保するためだったと言える。交通事故の直後、即死という形で父を失っていた場合はどうなっただろうか。いや、交通事故で即死する人も多いのだが(実際北大には交通事故で担ぎ込まれる患者も多く、それなりの数に方が亡くなっていた)、私の場合はそれは結果的に、何かを納得するための「時間」となった。

「さよならもいわずに」を読むと、階下で即死をしていた(心臓発作とうことになるのだろう)キホさんの姿が描かれる。配偶者を亡くしたときの愕然さと、通夜、葬儀の慌ただしさ、親戚の出入り、そしてそれでも仕事/生活があるという姿が描かれる。これを、父の死の前に読んだらどうなったのかとも思ったのだが、いや、いま本屋に入って手に取り買ってファミレスでパンケーキを食べながら読むという行為は「タイミング」と「感情移入」に尽きると思う。

癌で死ぬ、老衰で死ぬ、体調が悪くてそれがもとで死ぬ、という姿のひとつに、交通事故の後「モノ」を言うこと無く長く続き死ぬというパターンが私には加わった。私にとって父の死という現象は、実は大学に行った頃に既にあったものの、奇しくも私の失態により4年程も前に幾度となく父に迷惑を掛ける機会ができてしまい、その後、なんとなく家族に戻った。家を出るという(大学で一人暮らしをするとか、就職で一人暮らしを始めるとか)時には、既に自分の中の父は死に面している。だから、父がどのように呆けようと、札幌で年老いていようと、実家で床に臥せることがあろうと、気にしないつもりでもありそういう態度を貫き通していたものの、現実は私の楽観的な予想を裏切り、突然の交通事故の後、意識不明の2年間、そして死という経緯に至ることになった。

現実というものは、かくも厳しいものかと思われるかもしれないが、いや、急性肺炎で息を引き取る臨終の場所に居合わせ、通夜、葬儀という慌ただしい現実が過ぎるなか、父の遺体の横に居ても、病院のベットの横にいる感覚しかなかった。良くも悪くも、意識がなく、喋らない父が其処にいるだけだった。ベットは棺に変わり、顔の周りには暑い熱気を避けるためにドライアイスを置いていたものの、何も変わらない。仮通夜、通夜、葬儀の中でお坊さんがお経をあげていても、気持ちはあまり変わらなかった。
が、火葬場に父を運び「焼」かれる1時間を待ち、鍵で開けて骨だけとなった姿を見ると、もう戻りはしないという納得だけが残された。後付けであるが、お経も葬儀もなんらかの儀式は、その時間の経過と納得の時間を引き延ばすための手段なのだろう。少なくとも私の場合は信仰よりも、引き延ばされた現実の時間だけが残っている。

通夜から初七日までの間、いくつかのプログラムと原稿用紙15枚程度の文章を書いて「仕事」をしてみた。死よりも生を優先させるのが良いのは、それは日常に立ち返らなくてはいけないからだ。
ひとつ、幸いなのは2年前の交通事故の後は、日常は「危篤付き」の電話とともにあったのだが、今後はそれがないということだ。母にとっては2年間ほぼ休みなしの見舞い(看護自体は病院がやってくれるので、行く必要はないのだが)から解放されるということと同時に、その日常が消えてしまうということだ。だから、父が消えたというぽっかりと抜けた穴は、実は2年前に起こり、そして2年間で埋められつつあった穴がもういちど無くなったのかもしれない。いや、覚悟をする時間があったから、その穴は比較的浅かったと思う。

1時間ほど書いたの終わりにしよう。
月並みながら自分が生まれたことに感謝し、目の前の仕事に取り組む。

カテゴリー: 雑談 | さよならもいわずに はコメントを受け付けていません

[C#] HTMLをLINQで扱えるようにする(前哨戦)

諸事情で作る必要はなくなったのだけど、ExDoc の延長戦上にあるし、ということでぼちぼちと。
主旨としては、

Html Agility Pack
http://htmlagilitypack.codeplex.com/

と似たようなものです。Html Agility Pack を使ったことがないので(あとで観察するけど)正しい違いはどうか分からないのですが、今作っているものは、

・内部的には XML の整形式を使う。
・子ノードも含めて、LINQ(where)を簡単に実行できる。
・ノードの更新(Update/Remove/Insert)が簡単にできる。

を目標に作成しています。使い方の想定としては、既存のホームページを HTML 形式で抜き取った後に、HTML の整形、id や class などの無駄な属性の削除、javascript や comment などの削除、がさくっとできるツールをつくための、内部機関といったところです。

■目的

HTML 形式は XML 整形式ではないので、タグの入れ子などがややこしいのですが、最終的に PHP などで扱う場合には整形式にしておくと parse が楽なのです。XML 系のツールも使いやすいですからね。なので、ExDoc を少し改造した形で、内部を XML として扱います。

XML や HTML の子孫ノードは「//h1/div」のように XPath 形式が一番楽なのです。ですが、これは C#/VB では扱いにくい。コンパイルが通らないからね。なので、これに似た形で構文を書けるようにします。最初は、自作の ExDoc 形式「doc * “h1” / “div”」を考えていたのですが、更新作業を考えるとかなり面倒なので、LINQ 方式で Where メソッドのチェーンで書けるようにします。

doc.Where( x => x.TagName == "div" && x.Id == "m1" ).Vallue = "new message";

のような感じで、「<div id=”m1″></div>」の中身を「new message」に書き換えるパターンを、ワンライナーで書けるようにします。
無駄なタグを消したり、無駄な属性を消したりすることが多いことを考えて、HTML のタグを子孫ノードから直接見つけるようにします。何処にあるかわからないけど、ひとまず id を使って見つけられるという感じですね。

■手段

基本は、LINQ の where, select を使います。ただし、ツリー構造を追って探索するのは面倒なので、where メソッドをオーバーライドして子孫ノードまで探索するようにします。大抵は、class か id を使うのでこれで十分でしょう。

通常 where メソッドの戻り値は、リストか null になるのですが、プログラムが複雑になるので null は返さないようにします。そして、単数/複数を区別するのも嫌なので、HtmlElement あるいは HtmlElementCollection を返します。このあたりの制御は、ExDoc と同じように、暗黙のキャスト(implicit)を駆使します。

■仮実装

MSTest を使って、仮実装をします。基本的なメソッド名をだけを決めてテストコードを書いて実装、というテスト起動です。
ただし、最初の HtmlDocument を作るところだけは、実験を繰り返しながらブレークスルーを目指します。

namespace TestHtmlDom
{
    [TestClass]
    public class TestHtmlLinq
    {
        [TestMethod]
        public void TestTagName()
        {
            string html = @"<body><h1>title</h1>message</body>";
            HtmlDocument doc = new HtmlDocument(html);

            // var q = doc.documentElement.Children.Where(n => n.TagName == "h1");
            var q = doc.Where(n => n.TagName == "h1");
            Assert.AreEqual(1, q.Count);
            Assert.AreEqual("title", q[0].Value);
        }

        [TestMethod]
        public void TestTagName2()
        {
            string html = @"<body><h2>title1</h2>message<h2>title2</h2></body>";
            HtmlDocument doc = new HtmlDocument(html);

            var q = doc.Where(n => n.TagName == "h2");
            Assert.AreEqual(2, q.Count);
            Assert.AreEqual("title1", q[0].Value);
            Assert.AreEqual("title2", q[1].Value);
        }

        [TestMethod]
        public void TestTagName3()
        {
            string html = @"
<body>
    <h2>title1</h2>
        <span>message</span>
    <h2>title2</h2>
        <span>message2</span>
</body>
";
            HtmlDocument doc = new HtmlDocument(html);

            var q = doc.Where(n => n.TagName == "span");
            Assert.AreEqual(2, q.Count);
            Assert.AreEqual("message", q[0].Value);
            Assert.AreEqual("message2", q[1].Value);
        }

        [TestMethod]
        public void TestUpdate1()
        {
            string html = @"
<body>
    <h2>title1</h2>
        <span id='m1'>message</span>
    <h2>title2</h2>
        <span id='m2'>message2</span>
</body>
";
            HtmlDocument doc = new HtmlDocument(html);

            doc.Where(n => n.Attrs["id"] == "m2")
                .Update(n => n.Value = "new message");

            var q = doc.Where(n => n.TagName == "span");
            Assert.AreEqual(2, q.Count);
            Assert.AreEqual("message", q[0].Value);
            Assert.AreEqual("new message", q[1].Value);
        }

        [TestMethod]
        public void TestRemove1()
        {
            string html = @"
<body>
    <h2>title1</h2>
    <span id='m1'>message</span>
    <h2>title2</h2>
    <span id='m2'>message2</span>
</body>
";
            HtmlDocument doc = new HtmlDocument(html);

            doc.Where(n => n.Attrs["id"] == "m2").Remove();

            var q = doc.Where(n => n.TagName == "span");
            Assert.AreEqual(1, q.Count);
            Assert.AreEqual("message", q[0].Value);
        }

        [TestMethod]
        public void TestRemove2()
        {
            string html = @"
<body>
    <h2>title1</h2>
    <span id='m1'>message</span>
    <h2>title2</h2>
    <span id='m2'>message2</span>
</body>
";
            HtmlDocument doc = new HtmlDocument(html);
            var el = doc.Where(n => n.TagName == "span");
            doc.Remove( el );
            Assert.AreEqual(@"<body><h2>title1</h2><h2>title2</h2></body>", doc.Html );
        }

        [TestMethod]
        public void TestInsert1()
        {
            string html = @"
<body>
    <h2>title1</h2>
    <div id='m1'></div>
    <h2>title2</h2>
    <div id='m2'></div>
</body>
";
            HtmlDocument doc = new HtmlDocument(html);

            HtmlElement target = doc.Where( n => n.Attrs["id"] == "m1" );
            var el = target.AppendChild( new HtmlElement( "p", "new message" ));

            Assert.AreEqual("<body><h2>title1</h2><div id=\"m1\"><p>new message</p></div><h2>title2</h2><div id=\"m2\"/></body>", doc.Html );
        }
    }
}

まだ、検索系の where と更新系の update/remove/append を軽く実装しただけですが、結構いい感じに動いています。
テストを実行するために、Html プロパティを実装して、Assert.AreEqual をやりやすくしています。まだ Html プロパティを ReadOnly にしていますが、後々は書き込めるようにするということで。

■最初の HTML Document をどう作るか?

HTML が整形式ではない(タグの対応が揃っていない)ので、自前でパースしないといけないのか、とも思っていたのですが、mshtml.IHTMLDocument2 を使うことで比較手軽に HTML の DOM を作れます。

public HtmlDocument LoadHtml( string html )
{
#if false
    WebBrowser br = new WebBrowser();
    br.Navigate("about:blank");
    br.Document.Write(html);
    IHTMLDocument2 doc = (IHTMLDocument2)br.Document.DomDocument;
#else
    var doc = new HTMLDocument() as IHTMLDocument2;
    doc.write(new object[] { html });
#endif
    Load(doc);
    return this;
}

最初は、WebBrowser コントロールから DomDocument を取得しようと思ったのですが、mshtml.HTMLDocument クラスを使うことで HTML 文字列を直接扱えます。ノード自体を DOM で扱う場合には、IHTMLDocument2 を使うのでこれにキャストをします。
このあたりのノウハウはおいおいと公開しています。

カテゴリー: C# | [C#] HTMLをLINQで扱えるようにする(前哨戦) はコメントを受け付けていません

[C++] C++ で LINQ を実装してみるテスト(前哨戦)

ん~、前哨戦で終了するかもしれませんが、自分の勉強がてら。と、今使っているシステムにできれば組み入れたいので。
将来的に LINQ for C++ ができたとしても、VC++2010 に組み入れられるとは限らないので、やむなく自作ってところでしょうか。実験的なものでなので、拡張性/可読性を考えて導入するかどうかは決めましょう、ということで。

ラムダ式と std::function が使えるようになったから、じゃあ、LINQ らしいメソッドチェーンの方法を試してみたらと思ってざっと書いてみると。

GoingNative 9: LINQ for C/C++, Native Rx, Meet Aaron Lahman | C9::GoingNative | Channel 9
http://channel9.msdn.com/Shows/C9-GoingNative/GoingNative-9-LINQ-for-C-Native-Rx-RxC-Meet-Aaron-Lahman

ああ、確かに上記と同じ方法になります。

#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <tuple>
using namespace std;

class Vector : public vector<int> {
protected:
	Vector *_v;
public:
	Vector() :
		_v(NULL) {
	}
	~Vector() {
		if ( _v != NULL ) {
			delete _v;
		}
	}
	Vector &From( vector<int> &vec ) {
		// アップキャストしてるが、今回はこれで ^^;
		return *(Vector*)&vec;
	}
	Vector &Where(function<bool(int n)> func) {
		// 毎回 new しているが、遅延実行させるため iterator を使う予定
		if ( _v != NULL ) delete _v;
		_v = new Vector;
		for_each( begin(), end(),
			[=](int n) { if(func(n)) _v->push_back(n); });
		return *_v;
	}
	Vector &Select(function<int(int n)> func) {
		if ( _v != NULL ) delete _v;
		_v = new Vector;
		for_each( begin(), end(),
			[=](int n) { _v->push_back(func(n)); });
		return *_v;
	}
};


int main( void )
{
	Vector vec;
	for ( int i=0; i<10; i++ ) {
		vec.push_back( i );
	}
	
	auto query =
		vec.Where([](int &n)->bool{ return n % 2 == 0 ; })
		.Select([](int &n)->int{ return n*10 ; });
		
	for_each( query.begin(), query.end(),
		[](int n) { cout << n << endl; });
}

肝心の「遅延評価」ができていないので、LINQ とは言えませんが、まあ、表面上はコンパイルが通るし、実行も正常。

D:\work\blog\src\alice>lamda001
0
20
40
60
80

_v = new Vector() してから return *_v で method chain を実現しているんですが、これ memory leak してないか?と思ったのですが、調べるとリークしてませんね。参照で返しているのでブロック外に出ると自動的に解放されています。

元々の vecotr ではなくて、Vector を使わないと駄目なのは、駄目駄目なのでこれはなんとかしないと。
あと遅延評価は C# の IEnumable 相当を作るよりも、iterator をそのまま使いたいんですよね。やっぱり STL と互換性を持たせたいから。

カテゴリー: C++ | [C++] C++ で LINQ を実装してみるテスト(前哨戦) はコメントを受け付けていません

[c++] ラムダ式は std::function で保存せよ

関数ポインタを無理矢理取得して、別の関数ポインタに入れる方法 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/3580

なところで、関数ポインタを無理矢理 void * に入れて保存すれば ok ? と妄想していたのですが、いやいや、std::function を使えば lambda 式を保存できるよ、という話です。
要は、for_each や remove_if のような algorithm 系の関数に設定する関数をどうしたら class に押し込めるか?という問題だったので。

■実験用のソース

実験したコードはこんな感じです。

#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;

class Alice 
{
protected:
	vector<string> _lst;
public:
	Alice() {
		_lst.push_back("alice");
		_lst.push_back("luwis");
		_lst.push_back("lolita");
	}
	void disp1() {
		// lambda 式を直接扱う
		for_each( _lst.begin(), _lst.end(),
			[](string &s){ cout << "name: " << s << endl; });
	}
	void disp2() {
		// lambda 式を一度 auto 変数に入れる
		auto func = [](string &s){ cout << "name: " << s << endl; };
		for_each( _lst.begin(), _lst.end(), func );
	}
	
	// こんな風にクラスメソッドで扱うにはどうすればよいのか?
	void func(string s) {
		cout << "name: " << s << endl; 
	}
	void disp3() {
		// これはコンパイルエラー
		// for_each( _lst.begin(), _lst.end(), func );
		// これもコンパイルエラー
		// for_each( _lst.begin(), _lst.end(), mem_fun(&Alice::func));
		// 代替案として lambda でくるむ
		for_each( _lst.begin(), _lst.end(),
			[this](string s){ this->func(s); });
	}
	

	// std::function で定義	
	function<void(string)> func1 ;
	void disp4() {
		// コンストラクタ等で定義しておく
		this->func1 = [](string s){ cout << "name: " << s << endl; };
		// クラスの内部関数風に呼び出す
		for_each( _lst.begin(), _lst.end(), func1 );
	}
};

int main( void )
{
	Alice alice;
	
	alice.disp1();
	alice.disp2();
	alice.disp3();
	alice.disp4();
	
	return 0;
}

Alice::disp3 のように、Alice::func を表示用の関数として for_each から呼び出したいわけです。
普通に lambda 式を使うのが良いのですが、それを Alice クラスの内部関数として定義しておきたいわけです。これは、lambda 式の中身が複雑化したり複数の場所で使われるときに、一括管理しておきたいという想定です。lambda 式自体は auto 変数に代入しておくと、そのメソッド内では利用できるのですが、他では再利用できないので、クラス内のメンバ関数としようとしている訳です。

で、通常のメンバ関数の場合は &Alice::func のように取れるのですが、for_each に渡さないいけないのはグローバル関数か、要素のメソッドのなのです。この場合、vector としているので、要素の型である string に関数を仕込むのは無理があります。avoid な方法としては、string を一旦くるむ方法もありますが、かなり冗長です。

そこで出た代案としては、

		// 代替案として lambda でくるむ
		for_each( _lst.begin(), _lst.end(),
			[this](string s){ this->func(s); });

な方法です。非常にダサいですが、一度 lambda 式でくるんでメンバ関数を呼び出します。まあ、ダサいですが実用には耐えられますね。

じゃあ、ひょっとすると関数ポインタをなんらかの形で void * として保存しておいて、利用する時にもう一度元の関数型に直してやれば、動くのではないか?と思ったのが、「関数ポインタを無理矢理取得して~」の方法なのですが、いやいや、そこまでやる必要はなかったということです。

	// std::function で定義	
	function<void(string)> func1 ;
	void disp4() {
		// コンストラクタ等で定義しておく
		this->func1 = [](string s){ cout << "name: " << s << endl; };
		// クラスの内部関数風に呼び出す
		for_each( _lst.begin(), _lst.end(), func1 );
	}

std::function 型としてメンバ変数を定義しておき、その変数に lambda 式を代入しておきます。本来は、ここを本当のメンバ関数にしたいところですが、贅沢は言いません(苦笑)。これで実用に耐えられるので。
コンストラクタかなんらかの initialize 関数を作っておいて、lambda 式を変数に入れます。つまり、これは変数なので、型さえあっていれば、lambda 式を入れ替えることが可能なんですね。こうなると「for_each( _lst.begin(), _lst.end(), func1 );」の部分はまったく変えずに、func1 の中身だけすりかえしてまえば表示が変わるという仕組みができあがります。

これで、ひとまず目的は達成ということで。

カテゴリー: C++ | 2件のコメント

[c++] for_each と mem_fun の関係をメモ書き

c++ で lambda 式を使うと for_each を使うのが楽になる…のですが、一応、以前の書き方をメモ。

#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

static void f1( string s ) {
	cout << s << endl;
}

int main( void )
{
	vector<string> lines;
	lines.push_back("masuda");
	lines.push_back("tomoaki");
	lines.push_back("alice");

	// 普通にforを使う
	for( auto it=lines.begin(); it!=lines.end(); ++it ) {
		cout << (*it) << endl;
	}

	// for_each と lambda を使う
	for_each( lines.begin(), lines.end(),
		[](string s){ cout << s << endl; });

	// for_each と static 関数を使う
	for_each( lines.begin(), lines.end(), f1 );

	// for_each と auto 関数を使う
	auto f2 = [](string s){ cout << s << endl; };
	for_each( lines.begin(), lines.end(), f2 );

	return 0;
}

ノーマルに for 文を使って書くと一時変数が必要になる。auto が無かった時代には「vector::iterator it = lines.begin()」と書かないと駄目だったのですが、このあたりは auto を使えば十分。この長い書き方が嫌で typedef したりするのですが、今は不要です。

	// 普通にforを使う
	for( auto it=lines.begin(); it!=lines.end(); ++it ) {
		cout << (*it) << endl;
	}

for_each と lambda 式を使うとこんな感じ。iterator がそのままラムダ式の引数に入るのでそれを使えばOKです。
このあたりが LINQ っぽく書けるってことなのですが、このままではほど遠いかなと。まあ、慣れかもしれませんが、イテレーターを lambda 式の引数として受けないといけないのがいまいちです。

	// for_each と lambda を使う
	for_each( lines.begin(), lines.end(),
		[](string s){ cout << s << endl; });

lambda 式を auto で受けて関数ポインタとして使う方法です。lambda 式部分が長い場合や、動的に切り替えたい場合に使える…と思うのですがよくわからず。
本来は、この auto を関数の外側に出したいのですが、それを真面目に出すと…

	// for_each と auto 関数を使う
	auto f2 = [](string s){ cout << s << endl; };
	for_each( lines.begin(), lines.end(), f2 );

下記のように、処理関数を外側に出します。これだと普通ですね。というか、これが最初の for_each の使い方です。

static void f1( string s ) {
	cout << s << endl;
}

...
	// for_each と static 関数を使う
	for_each( lines.begin(), lines.end(), f1 );

■クラス内で for_each を使う

先の例では、main 関数内で使っていたのですが、今度はクラスのメソッド内で使ってみます。
使い方は、まあ、main 関数と一緒です。内部的に vector でコレクションを持っていて disp_for メソッドなり、一括で表示させる関数を想定しています。

class Alice
{
public:
	vector<string> lines;

	Alice() {
		lines.push_back("masuda");
		lines.push_back("tomoaki");
		lines.push_back("alice");
	}

	void disp_for()
	{
		// 普通のfor文
		for( auto it=lines.begin(); it!=lines.end(); ++it ) {
			cout << (*it) << endl;
		}
	}
	void disp_for_lambda() {
		// lambda 式を使う
		for_each( lines.begin(), lines.end(),
			[](string s){ cout << s << endl; });
	}
	void disp_for_auto() {
		// auto に代入して使う1
		auto f2 = [](string s){ cout << s << endl; };
		for_each( lines.begin(), lines.end(), f2 );
	}

	void f1(string s)
	{
		cout << s << endl;
	}
	void disp_for_inner_func()
	{
		// 出来そうで、できない???
		// for_each( lines.begin(), lines.end(), &Alice::f1 );
		// 素直に lambda 式から呼び出す
		for_each( lines.begin(), lines.end(),
			[this](string s){ this->f1(s); });
	}
};

main 関数とちょっと違うのは、以下の disp_for_inner_func メソッドのところです。
書き方としては、for_each で Alice クラスの内部関数 f1 を使いたいところなのですが…これは出来ません。
関数ポインタ「&Alice::f1」を使って、lambda 式のようにイテレーターを引数にして、と思って使ってみると、どうやってもコンパイルが通りません。

	void f1(string s)
	{
		cout << s << endl;
	}
	void disp_for_inner_func()
	{
		// 出来そうで、できない???
		for_each( lines.begin(), lines.end(), &Alice::f1 );
		// 素直に lambda 式から呼び出す
		for_each( lines.begin(), lines.end(),
			[this](string s){ this->f1(s); });
	}

VC++ でコンパイルと以下のようなエラーになります。

C:\Program Files\Microsoft Visual Studio 10.0\VC\INCLUDE\algorithm(22) : error C
2064: 1 引数を取り込む関数には評価されません。
        C:\Program Files\Microsoft Visual Studio 10.0\VC\INCLUDE\algorithm(32) :
 コンパイルされたクラスの テンプレート のインスタンス化 '_Fn1 std::_For_each<std
::basic_string<_Elem,_Traits,_Ax>*,_Fn1>(_InIt,_InIt,_Fn1)' の参照を確認してくだ
さい
        with
        [
            _Fn1=void (__thiscall Alice::* )(std::string),
            _Elem=char,
            _Traits=std::char_traits<char>,
            _Ax=std::allocator<char>,
            _InIt=std::basic_string<char,std::char_traits<char>,std::allocator<c
har>> *
        ]
        alice029.cpp(66) : コンパイルされたクラスの テンプレート のインスタンス
化 '_Fn1 std::for_each<std::_Vector_iterator<_Myvec>,void(__thiscall Alice::* )(
std::string)>(_InIt,_InIt,_Fn1)' の参照を確認してください
        with
        [
            _Fn1=void (__thiscall Alice::* )(std::string),
            _Myvec=std::_Vector_val<std::string,std::allocator<std::string>>,
            _InIt=std::_Vector_iterator<std::_Vector_val<std::string,std::alloca
tor<std::string>>>
        ]

実は、これは for_each の使い方が間違っているので、コンパイルエラーになるのです。

■メンバ関数は mem_func を使う。ただし要素のメンバ関数に限る

for_each で設定するループ関数は、実は「要素」に対するメソッドになります。lambda 式を使うと分かりづらいのですが、先の for_each では、vector の string に対して関数が適用される、という意味になります。
なので、メンバ関数を for_each に指定する場合は、そのメンバ関数を持つ要素クラスをつくらないと駄目なわけですよ。なるほど。

class Point {
public:
	int x, y, z;
public:
	Point(int x, int y, int z ) {
		this->x = x;
		this->y = y;
		this->z = z;
	}
	void disp() {
		cout << x << "," << y << "," << z << endl;
	}
};

int main( void )
{
	// mem_fun はこう使う
	vector<Point*> ps;
	ps.push_back( new Point(1,1,1));
	ps.push_back( new Point(2,2,2));
	ps.push_back( new Point(3,3,3));
	for_each( ps.begin(), ps.end(), mem_fun(&Point::disp));
}

こんな風に、Point クラスを作っておいて、disp メソッドがあるという場合を想定します。
vector コレクションに対して、for_each を適用すると、この disp メソッドを適用する、ということになるのです。
で、メソッド関数の場合にはそのまま適用できないので、上記のように mem_fun という補助関数を使います。内部的には、vecotr::iterator に対して disp メソッドを呼び出すという、関数ポインタを使うという作りになっています。

確かに、for_each だけでなく、remove_if や find_if のような比較関数を設定する場合、要素に対して comp 関数がある訳で、納得できる仕様ですよね。

ちなみに、find_if に比較関数 comp を追加して表示させるとこんな風になる。

class Point {
public:
	int x, y, z;
public:
	Point(int x, int y, int z ) {
		this->x = x;
		this->y = y;
		this->z = z;
	}
	void disp() {
		cout << x << "," << y << "," << z << endl;
	}
	bool comp( Point *pt ) {
		if ( this->x == pt->x &&
		     this->y == pt->y &&
		     this->z == pt->z ) {
			return true;
		} else {
			return false;
		}
	}
};

int main( void )
{
	Point *p1 = new Point(2,2,2);
	auto it = find_if( ps.begin(), ps.end(),
		bind2nd(mem_fun(&Point::comp),p1));
	if ( it != ps.end() ) {
		cout << "found." << endl;
	} else {
		cout << "no found." << endl;
	}
	return 0;
}

比較する Point ポインタを渡すために、bind2nd 関数を使うところが「アレ」ですが、まぁ、できます。
うーん、C++ template パズルを作りたい場合はこれでもいいのですが、実運用として(特に可読性としては)はこれはいまいちかなぁと常々思っています。

この comp という比較関数ですが、Point クラスに属さないと駄目なところが欠点ですよね。vector の場合はよいのですが、さて、vectorとか、vectorの場合はどうすれば良いのか?ってことです。比較関数として equal_to() とか使えばいいんですかね?

	auto b = find_if( lines.begin(), lines.end(),
		bind2nd( equal_to<string>(), "tomoaki" ));
	if ( b != lines.end() ) {
		cout << "found." << endl;
	} else {
		cout << "no found." << endl;
	}

まあ、慣れるとそれでもいいのですが、lambda 式があったり LINQ があったりする時代なので、ちょっとパズルは嫌だなぁと。
今だったら、下記のように lambda 式を使います。

	// lambda を使う
	auto b2 = find_if( lines.begin(), lines.end(),
		[](string s)->bool{ return s == "tomoaki"; });
	if ( b2 != lines.end() ) {
		cout << "found." << endl;
	} else {
		cout << "no found." << endl;
	}

このほうが可読性が高いです、と私は思います。

■プリミティブなクラスに比較関数をつけるのか?

で、話を戻すと、

	void disp_for_inner_func()
	{
		// 出来そうで、できない???
		// for_each( lines.begin(), lines.end(), &Alice::f1 );
		// 素直に lambda 式から呼び出す
		for_each( lines.begin(), lines.end(),
			[this](string s){ this->f1(s); });
	}

のところで、内部関数を渡せるほうが読み方としては私にはなんとなく自然な訳です。remove_if や find_if には equal_to のような関数が用意されていますが、カスタム表示のような disp 関数の場合は無理ですよね。
逃れる方法としては、ラムダ式からメンバ関数を呼び出すので、これで十分用途は足りるのですがなんかダサい。。。

class Point {
public:
	int x, y, z;
public:
	Point(int x, int y, int z ) {
		this->x = x;
		this->y = y;
		this->z = z;
	}
	void disp() {
		cout << x << "," << y << "," << z << endl;
	}
	bool comp( Point *pt ) {
		if ( this->x == pt->x &&
		     this->y == pt->y &&
		     this->z == pt->z ) {
			return true;
		} else {
			return false;
		}
	}
};

あと、発想として Point クラスに比較関数などなどが付け加わるのもいまいちなのです。Point クラスはデータクラスとして必要最低限にとどめておきたいし、のちのちに拡張させないようにしたい。C++ 的には include 先が変更されるのは避けたいわけで、そうなると「将来追加されるかもしれない」comp 関数などを追加しておくのは「到底無理」な訳です。
そうなると、comp 関数のほうも使うときに適宜用意するのが適当で、

Alice {
	vector<Point*> ps;
public:
	bool comp( Point *p1, Point *p2 ) {
		if ( p1->x == p2->x &&
             p1->x == p2->y &&
             p1->x == p2->z ) {
			return true;
		} else {
			return false;
		}
	}
	bool find( Point *p ) {
		return for_each( ps.begin(), ps.end(),
			&Alice::comp, p );
	}
};

な風に、2つの引数を持つ comp メソッドを for_each から直接呼び出せたらよいなぁ、と。comp メソッドの中身はここでは x,y,z の全てを比較していますが、workarea などを含めると独自に comp を作ったほうが良い場合が多いのです。高速化のために内部的には id を比較するだけとか。

あとは、LINQ 風に

bool find( Point *p ) {
	return ps.from( it ).where(it == *p );
}

あるいは

bool find( Point *p ) {
	auto result = ps.from(it).where(it==*p);
	return result != ps.end();
}

としてしまうとか。まあ、こっちのは話はまた別の機会に。

カテゴリー: C++ | 2件のコメント

C++ で ObservableCollection を実装する

ObservableCollection(T) クラス (System.Collections.ObjectModel)
http://msdn.microsoft.com/ja-jp/library/ms668604.aspx
Skeleton of GOF’s Design Pattern
http://www002.upp.so-net.ne.jp/ys_oota/mdp/Observer/index.htm

2つのViewの変更が、同時に行われるときのModelの挙動を考察 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/3575

で、__event/__hook で実装しようと思っていたのですが、基本に帰って Observer パターンを調べてみると、ああ、これでいいじゃんということにしました。車輪の再発明ってやつです。

  • View と Data/Model を独立させよう
  • Model の変更を複数の View に伝える

という点も従来の Observer パターンで ok です。
このあたり、notify で渡す時に、notify( Model * ) のように Model の型を渡してしまうと Model の型に縛られる(当たり前)ってことになるのですが、ここは object 型/void *で十分な訳です。受ける側で、(Model*)object としてキャストをすれば良いわけで…なるほど。

複数の view への通知に対しては、addObjserver/revemoOPbserverを実装して通知先の Observable をコレクションしておきます。元々の Observer パターンがこうなので、私の見落としですね。

で、GridView と データコレクションとの連携、いわゆるコレクションのデータバインドに関しては、ObservableCollection が良く使われるので、これを C++ で実装してみます。

// Doc-View に直す暫定 Observable パターン
#include <string>
#include <iostream>
#include <list>
#include <algorithm>

using namespace std;

class IObserver {
public:
	// Action
	enum Action {
		Add,
		Remove,
		Replace,
		Move,
		Reset,
	};
	virtual void CollectionChanged( void *ob, Action mode ) {}
	virtual void PropertyChanged( void *ob, const char *propName ) {}
};

class IObservable {
protected:
	std::list<IObserver*> _lst;
public:
	void addObserver( IObserver *ob ) {
		_lst.push_back( ob );
	}
	void removeObserver( IObserver *ob ) {
		_lst.remove( ob );
	}
	void notify( const char *propName ) {
		for ( auto it = _lst.begin(); it != _lst.end(); ++it ) {
			(*it)->PropertyChanged( this, propName );
		}
	}
};

template <class T> class ObservableCollection : public std::list<T> {
protected:
	std::list<IObserver*> _lst;
public:
	void addObserver( IObserver *ob ) {
		_lst.push_back( ob );
	}
	void removeObserver( IObserver *ob ) {
		_lst.remove( ob );
	}
	void notify( T item, IObserver::Action mode ) {
		for ( auto it = _lst.begin(); it != _lst.end(); ++it ) {
			(*it)->CollectionChanged( item, mode );
		}
	}
public:
	// override
	void push_back( T item ) {
		std::list<T>::push_back( item );
		notify( item, IObserver::Add );
	}
	void remove( T item ) {
		std::list<T>::remove( item );
		notify( item, IObserver::Remove );
	}
	void removeAt( int index ) {
		for ( auto it=begin(); it!=end(); ++it ) {
			if ( index-- == 0 ) {
				remove( *it );
			}
		}
	}
	void insert( std::list<T>::iterator it, T item ) {
		std::list<T>::insert( it, item );
		notify( item, IObserver::Add );
	}
		
	void insertAt( int index, T item ) {
		for ( auto it=begin(); it!=end(); ++it ) {
			if ( index-- == 0 ) {
				insert( it, item );
			}
		}
	}
	void clear() {
		std::list<T>::clear();
		notify( item, IObserver::Reset );
	}
};

#define PROPERTY( _t, _m ) \
public:	_t m_##_m;	\
public:				\
	__declspec(property(get=get##_m,put=set##_m)) _t _m;	\
	_t get##_m() { return m_##_m; }	\
	void set##_m( _t v ) {			\
		if ( m_##_m != v ) {		\
			m_##_m = v;				\
			notify( #_m );			\
		}							\
	}

class Data : public IObservable {
public:
	PROPERTY( string, Name );
	PROPERTY( int, Age );
public:
	Data( string name, int age ) {
		this->m_Name = name;
		this->m_Age = age;
	}
};
class View : public IObserver
{
public:	
	virtual void CollectionChanged( void *sender, IObserver::Action mode ) 
	{
		Data *data = (Data*)sender;
		cout << "name: " << data->Name << " " << mode  << endl;
	}
	virtual void PropertyChanged( void *sender, const char *propName ) 
	{
		Data *data = (Data*)sender;
		cout << "name: " << data->Name << " " << propName  << endl;
	}
};

int main( void )
{
	ObservableCollection<Data*> lst;
	
	lst.push_back( new Data( "masuda", 20 ));
	lst.push_back( new Data( "tomoaki", 30 ));
	lst.push_back( new Data( "alice", 10 ));
	
	View view;
	// append handler
	lst.addObserver( &view );
	for_each( lst.begin(), lst.end(), 
		[&view](Data *v){ v->addObserver( &view );});
	
	Data *d = new Data( "nanashi", 20 );
	d->addObserver( &view );
	// append item
	lst.push_back(d);
	// change property
	d->Name = "NANASHI";
	
	return 0;
}

C#/VB の ObservableCollection と合わせるために、CollectionChanged と PropertyChanged というイベントが発生します。通知元の Model/Data では IObservable を継承して、通知先の View では IObserver を継承します。__event/__hook を使うと、直接メンバ関数にマッピングができるので継承自体がいらないのですが、名称の統一性を考えると明示的に継承したほうがよさそうです。

Collection にした場合、それぞれの要素の IObserver のコレクション _lst が無駄に思えるので、もう少し改修は必要でしょうねぇ。まぁ、昨今のメモリ事情ならばこのままでも良いかと。

IObserver/IObservable というインターフェースのような名前にしていますが、実装が入っています。純粋関数にしても良いのですが、継承するけど通知されたくない(?)という中途半端な状態でも ok なので、これでよいかと。

カテゴリー: C++ | C++ で ObservableCollection を実装する はコメントを受け付けていません