コードで学ぶASP.NET MVC の目次

自分で忘れる…ってのと、目次のリンク先が自動リンクなので、直リンクにした目次を

連載! コードで学ぶ ASP.NET MVC アプリケーション開発入門 | Code Recipe | MSDN

しかし、この MSDN コード サンプル ギャラリー のところに、「ASP.NET MVC」のキーテクノロジはないんですよね。でも連載記事のほうには ASP.NET MVC というキーがあるので、不具合なのかなぁと思ったり、思わなかったり。

# あとでフィードバックを送っておこうッ!!!

カテゴリー: ASP.NET | コードで学ぶASP.NET MVC の目次 はコメントを受け付けていません

PHPでEXDocを作ってみる(準備)

C# で大方 EXDoc が動いたので、本命(?)の PHP で動かしてみるテスト。
いや、単純に

PHP: マジックメソッド – Manual
http://www.php.net/manual/ja/language.oop5.magic.php

を使えば、XML のタグ名や属性を直接書けるのでは?という思いつきです。

まずは、UIDD に従って、こんな風にコードが書けたらいいなぁ、というコードを作ります。

$doc = new EXDoc();
$els = $doc->members->person;
$els = $doc->members->person("name")->eq("masuda");
$doc->members->person("name")->value = "masuda";

何をやっているか分かりますよね。PHP の場合は / 演算子などの多重定義ができないので、普通にメソッド/プロパティ呼出しをします。
この、-> 演算子のところで、直接 members やら person やらを書くわけですが、これがメソッド名だったりプロパティ名だった利する訳です。

で、当然、このメソッドは定義していないのでエラーになります。が、PHP のマニュアルに書いてあるマジックメソッドを使うと、未定義のプロパティやメソッド名のエラーを拾うことができるのです。

これに対処したのが次の例。

<?php
class EXDoc
{
	function __call($name,$args) {
		print &quot;func $name(&quot;;
		foreach( $args as $a ) {
			print &quot;$a &quot;;
		}
		print &quot;)\n&quot;;
		return new EXDoc();
	}
	function __get($name) {
		print &quot;get $name\n&quot;;
		return new EXDoc();
	}
	function __set($name,$value) {
		print &quot;set $name $value\n&quot;;
		return new EXDoc();
	}
}

C# よりも更に簡単になります。未定義の関数やプロパティは、 __call __get, __set メソッドで取れるので、ここで、さらりと EXDoc を new して返してやります。すると、先のコードがするするととおって、次の実行結果が得られます。

D:\work\blog\src\php>php ex001.php
get members
get person
get members
func person(name )
func eq(masuda )
get members
func person(name )
set value masuda

見事にエラーも出さずに、目的が(半分だけ)達成ッ!!!
# 確か、Ruby には動的にプロパティを作る方法があるのですが、PHP のように未定義のメソッドを拾うことができたかどうかは不明です。

あとは、内部的に SimleXML か DOM を使って操作すればOKってことで。

カテゴリー: 開発, UIDD, EXDoc | 2件のコメント

tweetbackup もどきを作ってみる

ツイッターの全発言を取得する perl スクリプトを以前書いたので、

指定したTwitterアカウントの全ツイートを取得(perl版)
http://www.moonmile.net/blog/archives/860

今回は、C# を使ってもう少し分かりやすく書き直します。ひとまず、抜粋だけアップして、後でツールをアップということで。

    public class TwiBack
    {
        protected string _user;
        /// <summary>
        /// アカウント
        /// </summary>
        public string User
        {
            get { return _user; }
            set { _user = value; }
        }

        protected const string HTTPTWI = &quot;http://twitter.com&quot;;

        /// <summary>
        /// ツイート数
        /// </summary>
        /// <returns></returns>
        public int GetTweetCount()
        {
            string url = string.Format(&quot;{0}/{1}&quot;, HTTPTWI, _user);

            WebClient web = new WebClient();
            StreamReader sr = new StreamReader( web.OpenRead(url));

            // <span id=&quot;update_count&quot; class=&quot;stat_count&quot;>2,153</span>
            Regex rx = new Regex(&quot;>([0-9,]+)<&quot;);
            while (sr.EndOfStream == false)
            {
                string line = sr.ReadLine();
                if (line.IndexOf(&quot;<span id=\&quot;update_count\&quot;&quot;) >= 0)
                {
                    Match mt = rx.Match(line);
                    int count = int.Parse(mt.Groups[1].Value.Replace(&quot;,&quot;, &quot;&quot;));
                    return count;
                }
                // Console.WriteLine(line);
            }
            return 0;
        }

        /// <summary>
        /// ページ番号でツイートを取得
        /// </summary>
        /// <param name=&quot;page&quot;></param>
        /// <returns></returns>
        public string GetTweetPage(int page)
        {
            string url = string.Format(&quot;{0}/{1}?page={2}&quot;, HTTPTWI, _user, page);

            WebClient web = new WebClient();
            StreamReader sr = new StreamReader(web.OpenRead(url));

            // <li class=&quot;hentry u-moonmile status&quot; id=&quot;status_41673902056935425&quot;
            List<string> lines = new List<string>();
            while (sr.EndOfStream == false)
            {
                string line = sr.ReadLine();
                if (line.IndexOf(&quot;<li class=\&quot;hentry&quot;) >= 0)
                {
                    lines.Add(line + &quot;\n&quot;);
                    while (sr.EndOfStream == false)
                    {
                        line = sr.ReadLine();
                        lines.Add( line + &quot;\n&quot; );
                        if ( line.IndexOf(&quot;</li>&quot;) >= 0 ) {
                            break;
                        }
                    }
                }
            }
            string ss = &quot;&quot;;
            foreach ( string s in lines ) {
                ss += s ;
            }
            return ss ;
        }

        /// <summary>
        /// ツイートXMLをコンバート
        /// </summary>
        /// <param name=&quot;xml&quot;></param>
        /// <returns></returns>
        public string ConvXml(string xml)
        {
            EXDoc.EXDocument doc = new EXDocument();
            doc.LoadXML(xml);

            EXDocument dout = new EXDocument();
            // ルート要素を作る
            dout += &quot;tweets&quot;;
            // 変換元をループ
            foreach (EXElement twi in doc * &quot;li&quot; )
            {
                // 変換元から取り出す
                string id = twi[&quot;id&quot;].Replace(&quot;status_&quot;, &quot;&quot;);
                string content = ((EXElement)(twi * &quot;span&quot; % &quot;class&quot; == &quot;entry-content&quot;)).Xml;
                string date = twi * &quot;span&quot; % &quot;class&quot; == &quot;published timestamp&quot;;

                Console.WriteLine(id);
                // 要素を作る
                EXElement tweet = dout.Root.Append(&quot;tweet&quot;);
                tweet.Append(&quot;id&quot;).Value = id;
                tweet.Append(&quot;content&quot;).Value = content;
                tweet.Append(&quot;date&quot;).Value  = date;
            }
            return dout.Xml;
        }
    }

TwiBack クラスの中で、GetTweetCount メソッドと GetTweetPage メソッドはノーマルに Twitter の Web ページから発言数と発言を取得しているところです。perl 版と同様に、ブラウザ経由で取得するので、アクセス数制限はありません。ただ、返信とかしているのは取れないので、いまいちですけどね。このあたりは、OAuth でログインした後にブラウザ経由で取るように修正してきます。

# 当初の目的が人様の発言を全部取ってくるので、バックアップとはちょっとニュアンスが違うのです。

で、取得した HTML タグは、以下の形式で取得できます。

<li class=&quot;hentry u-moonmile status latest-status&quot; id=&quot;status_42686164938932224&quot;>
	<span class=&quot;status-body&quot;>
		<span class=&quot;status-content&quot;>
        	<span class=&quot;entry-content&quot;>【メモ】 クローラのせいで重くなった MT4i の対策 - Movable Type運営記
<a href=&quot;http://bit.ly/es5CWf&quot; class=&quot;tweet-url web&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;>http://bit.ly/es5CWf</a> -- 以前から気になっていたけど、yeti は韓国系のクローラーなのか。これもブロック。</span>
        </span>
    	<span class=&quot;meta entry-meta&quot; data='{}'>
  			<a class=&quot;entry-date&quot; rel=&quot;bookmark&quot; href=&quot;http://twitter.com/moonmile/status/42686164938932224&quot;>
    		<span class=&quot;published timestamp&quot; data=&quot;{time:'Tue Mar 01 20:42:29 +0000 2011'}&quot;>12:42 PM Mar 1st</span>
    		</a>
  		<span><a href=&quot;http://moonmile.net/&quot; rel=&quot;nofollow&quot;>TwiNetBot</a>から</span>
  		</span>
        <ul class=&quot;meta-data clearfix&quot;></ul>
  	</span>
</li>

このままだと使いづらいので、分かりやすいように整形します。ってところで普通ならば LINQ to XML を使うのでしょうが、ええッそうですッ!!! 自前の EXDoc を使います。

/// <summary>
/// ツイートXMLをコンバート
/// </summary>
/// <param name=&quot;xml&quot;></param>
/// <returns></returns>
public string ConvXml(string xml)
{
    EXDoc.EXDocument doc = new EXDocument();
    doc.LoadXML(xml);

    EXDocument dout = new EXDocument();
    // ルート要素を作る
    dout += &quot;tweets&quot;;
    // 変換元をループ
    foreach (EXElement twi in doc * &quot;li&quot; )
    {
        // 変換元から取り出す
        string id = twi[&quot;id&quot;].Replace(&quot;status_&quot;, &quot;&quot;);
        string content = ((EXElement)(twi * &quot;span&quot; % &quot;class&quot; == &quot;entry-content&quot;)).Xml;
        string date = twi * &quot;span&quot; % &quot;class&quot; == &quot;published timestamp&quot;;

        Console.WriteLine(id);
        // 要素を作る
        EXElement tweet = dout.Root.Append(&quot;tweet&quot;);
        tweet.Append(&quot;id&quot;).Value = id;
        tweet.Append(&quot;content&quot;).Value = content;
        tweet.Append(&quot;date&quot;).Value  = date;
    }
    return dout.Xml;
}

なんか不思議な記号がいっぱいになってきてしまいましたがw、変換元から、

・id
・content(発言)
・date(発言した日時)

を拾ってきて、

<tweet>
	<id>...</id>
	<content>...</content>
	<date>...</date>
</tweet>

な形に整形します。

要素を追加するのに、いろいろ多重定義する演算子を探してみたのですが、結局のところ、Append メソッドに落ち着きました。デリゲートの追加演算子のように += 演算子を使おうとしたのですが(実装はしています)、+= 演算子を使った後に、追加した要素が取れないことになるので、やめました。

C++ だと、

EXElement *tweet = dout.Root += "tweet";
(tweet += "id") = id;
(tweet += "content") = content;
(tweet += "date") = date;

な感じで作れるんですけどね…C# だと左辺に式を置けないので、これができないのです。
あと、cout などで定番の << 演算子も C# ではなぜか数値しか使えないので、【使えない】演算子になっています。このあたりの制限が、C# はかなり変です。

とは言え、メソッドチェーンと配列を使いながら、イメージしやすい形でコーディングができます。特に、XML を作成するときは、Append を続けて子を作っていくというのがイメージしやすいと思います。これが普通の XML の構築だと、CreateNode した後に、AppendChild するので、なんか作成と挿入が遠い感じになってしまいます(まあ、作成した途端に追加すればいいだけなんですけどね)。

カテゴリー: C# | tweetbackup もどきを作ってみる はコメントを受け付けていません

RIA とは違う UIDD を模索中(準備)

RIA(Rich Internet Application)とか、UX(User eXperience)とは違った形で、UIDD(User Interfece Driven Developement)を考えようと思って、ネタ的にドメインを取ってみました。

http://uidd.net

ええ、com のほうは、$1000 ぐらいで売っているものですからw それなりに需要はあるのか、ないのか。

EXDoc を作りながら、久し振りにロジック関係に NUnit を使っていた訳ですが、やっぱりこの手のライブラリを作る手順としては、

  1. 利用者がどうつかうのか、を具体化する。
  2. その機能を実現する。

という UI 先行型のほうが良いです。この考え方自体は、RIA とか UX 以前に、ペーパープロトタイピングだとか、ペルソナ指向開発なんかがあって、アジャイル開発と相まって使われるのですが、なんだかんだと私は良く使います。
これが、普通の開発だと、

  1. 要件定義をする。要求を取り込む。
  2. 設計をする

という形で、設計のほうが後に来るもので、要件やら要求やらの曖昧なものが形になって、いざ利用するための設計(デザイン)をする段階で、最初の要求(requirement)とのミスマッチングが起こります。この「デザイン」という言葉はかなり語弊を含んでしまうのですが、2つの意味があります。

  • 見た目をデザインする。
  • 機能、利用法をデザインする。

という意味です。工業デザインの場合は、両方を考えないといけないので(例えば、いくら美しくても穴のあいたコップや、テーブルに置いただけのコップでは利用価値はないですよね)普段から行われていることなのですが、コンピュータ関係のデザインというと、この機能/利用法が欠け落ちてしまっていることが多々あります。

いわゆる UX にしても「利用価値/利用のしやすさ」の追求よりも「見ための美しさ」を追及するところが多いのです。営業的にそれがプッシュされるのも分からないでもないのですが、ずーっと、いまいちな感じがしていました。

RIA についても同じで、何故か Internet を含んでいるので、インターネットを使ったブラウザ上のという制限が付きまといます。いや、Internet だからブラウザである必要はないのですが、どうもその手の話が多い。ブラウザで使おうが、Windows アプリで使おうが、iPad のアプリで使おうが、それは利用者の選ぶところであって、提供側の選ぶところではありませんよね。なので、この制限も変な話かなぁと思っていました(

ええ、勿論営業的にプッシュするは悪くないし、そういうことは大いにやるべきことかと。

という訳で、ネタ的にではありますが、uidd.net というドメインで、もっとシビアな形で UI を実践していこうかなぁと考えました。シビアにというと、どのくらいシビアなのか、という例をだしてみると、

  • LINQ やメソッドチェーンの文法は、C# や Java の文法から外れないように作られているだけで、本来やりたいこととは別の路線に乗ってしまっているような気がする。なので、文法の制限を外してでも、本来やりたいこと(プログラマがコーディングをするという意味で)の文法を定義するべきではないだろうか?

ってなことで、

  • C# にはやっぱり、マクロが必要だよね、とか。
  • C# の左辺に変数しか入れられないのは変だよね、とか(C++は入れられる)
  • C# は拡張メソッドを入れたため、ぐだぐだになったよね、とか。
  • Java のインターフェース一杯は、変だよね、とか。
  • try-catch って、文法的に変だよね、とか

そんな話とか、HTML5 絡みで、やっぱり SVG は復活させるべきだろう、ってな感じで、

  • Flash を作るように SVG がつくれないと絶対普及しないよね、とか。
  • SVG を扱う javascript ってプログラマ寄りだから、デザイナは使わないよね、とか。
  • SVG を扱うときも、MVC で分離させようね、とか。
  • MVC で、View をテンプレート化させると、デザイナが使わないから普及しないよね、とか。

な話です。

まあ、これを IT以外の利用者に拡大していくわけで、例えば、

  • 車のハンドルは、右左ボタンじゃあ危なくってしょうがないよね、とか。
  • 車の動態認識は、ブレーキとハンドルさばきが一体化しないと意味ないでしょ、とか。
  • 実現してほしいのは iPhone とかのスマートフォンじゃなくて、クレジットカードタイプのタッチパネルでしょ、とか。
  • タッチパネルも、1枚じゃななくて、複数枚用意してしかるべきでしょ、とか(ボタン毎に液晶パネルを付けてもOKだし)。

まぁ、そんな実現と非実現のあたりをそれなりにという話。

カテゴリー: 設計, UIDD, 雑談 | RIA とは違う UIDD を模索中(準備) はコメントを受け付けていません

もう LINQ to XML はいらない(虚実編)

今度は、比較演算子をオーバーライドします。

まず、どんなことがやりたいかというと、

<members>
    <person name='masuda'>masuda tomoaki</person>
    <person name='yamada'>yamada taro</person>
</members>

こんな風な XML があったときに、name 属性が “yamada” の要素をとりたいとします。

この場合のコードを

EXElement el = doc / "members" / "person" % "name" == "yamada";

と書きたい訳ですね。LINQ の文法で言えば、where 句があって、ってことになるのですが、そんな面倒なことを EXDoc ではやりませんッ!!! と言いますか、このあたりがコード上のシンタックスシュガーな訳なのです。

% 演算子を使って属性の値が取れるので、これを == 演算子で比較します。
普通は、bool 値で true/false で返すのですが、それでは意味がないのですね。どうせならば、マッチする要素を取って来てほしい。

なので、== 演算子の戻り値を、bool 型じゃなくて、EXElements 型にしてしまいますw
なんか、後で破綻しそうな気もしますが、別に構いません。C# の文法に則ったまま、ちょっと不思議な言語を作っている気分なので。

そんな訳で、== 演算子を多重定義します。

public static EXElements operator ==(EXAttrs ats, string val)
{
    EXElements items = new EXElements();
    foreach (EXAttr at in ats)
    {
        if (at.Value == val)
        {
            items.Add(at._exElement);
        }
    }
    return items;
}
public static EXElements operator !=(EXAttrs ats, string val)
{
    EXElements items = new EXElements();
    foreach (EXAttr at in ats)
    {
        if (at.Value != val)
        {
            items.Add(at._exElement);
        }
    }
    return items;
}
public override bool Equals(object obj)
{
    return base.Equals(obj);
}
public override int GetHashCode()
{
    return base.GetHashCode();
}

どうやら、== 演算子を多重定義すると自動的に、

・!= 演算子
・Equals メソッド
・GetHashCode メソッド

もオーバーライドする必要があるので、適当に入れておきます。

こうすることで、

EXElement el = doc / "members" / "person" % "name" == "yamada";

このコードが、思った通りに動くようになります。

そう、これって UIDD(User Interface Driven Development)と言ってもいいかもとか、思いました。あるいは、You & I Driven Development とか。

一応 wikipedia にもあるみたい。ちょっと違いますが。
http://ja.wikipedia.org/wiki/UIDD

カテゴリー: 開発, C# | もう LINQ to XML はいらない(虚実編) はコメントを受け付けていません

もう LINQ to XML はいらない(謀略編)

既にいくつかの機能を追加してしまったので、実装は先に進んでいるのですが、ちょっと文字列(string)絡みのところを。

// ルート要素を取得する
   EXElement el = doc / "members";

// person 要素を取得する
   EXElements els = doc / "members" / "person";

このように、きっちりと型に保存してもいいのですが、最近の流行は型推論ですよね。
なので、C# 3.0 の場合は、var を使って

// ルート要素を取得する
   var el = doc / "members";

// person 要素を取得する
   var els = doc / "members" / "person";

のようにしてもいいのですが、今回は【型推論】のアプローチじゃなくて、【厳密な型宣言】を応用していきます。つまりは、暗黙のキャスト(implicit)を使っているように見えて、変換先の型が振る舞いを変えている、という受け側の【型】が重要になるというアプローチです。
型推論の場合は、最初に型が決定していなくて後から決定する場合でも OK ってな感じですが、自分が使いやすい型に当てはめる形で値を受け取る、という違うアプローチなのですね…って、本当に違うのかどうか、よく分からないのですが、なんとなく対照性があるかなぁと。

さて、次のコードを見てください。

// ルート要素を取得する
   string val = doc / "members";

// person 要素を取得する
   string[] vals = doc / "members" / "person";

この場合、string と sting[] 型が明示的に使われています。members 要素の値を文字列で受け取りたい、複数ある person 要素の値を文字列の配列で受け取りたい、という【意図】がこの時点で明確になります。
ここで var の場合を使ってしまうと、この時点では、string に入れようとしているのか、EXElement に入れようとしているのか分かりません。

こんな風に、【型を厳密に】指定することによるメリットが大きいわけです。

# 当然ですが、この技は Ruby や PHP などの型がないスクリプト言語では使えません。もし、型のあるスクリプト言語があれば(私はよく知らないのですが)、このアプローチが取れます。

更に、不思議なアプローチを紹介しましょう。

// person 要素を配列で取得する
   string[] vals = doc / "members" / "person";

// person 要素をひとつ取得する
   string val = doc / "members" / "person";

この例では、doc/members/person の配列あるい文字列を取得します。
同じように指定しているのに、配列で取れたり、文字列だけで取れたりするのは不思議でしょう?

でも、この書き方は XML を解析する側としては、明白なことでもあるのです。
XML からデータを取得する場合、あらかじめ XML のデータ構造が分かっていることが多いのです。DTD を指定されないとしても、大まかな構造が分かっている場合がほとんどでしょう。

そうなれば、/members/person が単数なのか、複数なのかは、プログラミングをするときに決まっていますよね。
なので、どうせ XML 構造を把握しているのであれば、それを利用して、単数の string も同様に取れるようにしてしまうほうが自然です。

# たとえば、ファミレスの店員が、ひとりのお客を目の前にして「ただいま、20名のお客様は入れません」と言うことはない…訳でもないけれど、ほぼ無いですよね。まずは「おひとりでしょうか?」と尋ねるのが自然です。

なので、単数で取るのか、配列で取るのかをプログラミングしているときに分けるのも自然です。っていうのが、このコードの主旨です。

と、長々と書きましたが、実はコードが非常に短いからなのです。EXElements クラスができているので、これを string[] や string にキャストするメソッドを作ります。

public class EXElements : List<EXElement>
{
	/// <summary>
	/// 文字列の配列にキャスト
	/// </summary>
	/// <param name=&quot;els&quot;></param>
	/// <param name=&quot;tag&quot;></param>
	/// <returns></returns>
	public static implicit operator string[]( EXElements els ) 
	{
	    List<string> items = new List<string>();
	    if (els.Count > 0)
	    {
	        foreach (EXElement el in els)
	        {
	            items.Add(el.Value);
	        }
	    }
	    return items.ToArray();
	}

	/// <summary>
	/// 文字列にキャスト
	/// </summary>
	/// <param name=&quot;els&quot;></param>
	/// <returns></returns>
	public static implicit operator string(EXElements els)
	{
	    if (els.Count == 0)
	    {
	        return &quot;&quot;;
	    }
	    else
	    {
	        return els[0].Value;
	    }
	}
}

馬鹿馬鹿しいほど、簡単なコードですね。implicit で暗黙にキャストを指定しておいて、キャスト先の string[] あるいは string にあわせるだけです。

さて、お次は比較演算子(==)を多重定義して、属性の値によって抽出をしてみます。

カテゴリー: 開発, C# | もう LINQ to XML はいらない(謀略編) はコメントを受け付けていません

アリスは括弧がお嫌い

アリプラシリーズの python 版…と言いますか、ちょっと C++ との比較。
perl 以外で適当なスクリプト言語を、と思っていたので、ruby にしようか、何にしようかと思っていたのですが、python を使ってみました。

で、ちろっと使ってみて、これはッ!!! と思ったのが括弧が少ないことです。
python 特有のタブ(空白でもOK)で揃える書式は、終わりの括弧を少なくするんですね。これって、XML と SOX の関係に似ていて、

<members>
	<person>
		<name>masuda tomoaki</name>
	</person>
</member>

のように XML では閉じタグが必要なのですが、SOX にはいりません。

members>
	person>
		name>
			masuda tomoaki

先の.NET勉強会でXMLのディスカッションの中で、XML はログ出力のようなものには向かない、と言いましたが、SOX はログ出力には向くのです。何故ならば閉じタグがないからです。

この閉じるという処理は、開始と終了が明確になると同時に、閉じるためには、開かないといけない、という作業が発生します…って、禅問答みたいで、なんだか分かりませんね。

例えば先の XML の例だと、新しく person タグを追加する場合には、

  1. mebers 閉じタグの前に書かないといけない。
  2. person の開始タグと終了タグを書かないといけない。
  3. name タグを挿入しないといけない。

という挿入の作業が発生します。これを SOX の場合では、

  1. person タグを追加する。
  2. name タグを追加する。

という追加の作業だけでいいんですね。この後ろに追加していく感覚は、プログラミングにおいても前から後ろへ書いていくという感覚と一致して、非常にやりやすいのです。
なので、LINQ が from から始まるのもその理由ですね。SQL が SELECT から始まるので若干やりづらいので、いきなり SELECT * FROM から書き始めてから、* 部分を書き直していきます。

さて、python は括弧が少ないので、こんな風に alice が書けます。

import sys
args = sys.argv
argc = len(args)

if argc == 1:
	print "alice don't like parentheses."
	print "please input parameters of this program."
else:
	for i,p in enumerate(args):
		print "%d: %s" % (i,p)

慣れも必要なんでしょうけど、インデントが深くなる時は、「:」を打つルールがあるみたいです(みたいです、と書くのは私が初学者だから)。

で、これを素直に C++ で書き直すと、

#include <iostream>
using namespace std;

// アリスは括弧がお嫌い
int main(int argc, char *argv[] )
{
	if ( argc == 1 ) 
		cout << &quot;Alice は括弧がお嫌い&quot; << endl,
		cout << &quot;何かパラメータを指定してッ!!!&quot; << endl;
	else
		for ( int i=0; i<argc; i++ ) 
			cout << i << &quot;:&quot; << argv[i] << endl;
}

え?何これ?って感じですが、中括弧を省くことができます。
まぁ、if 文や for 文の後の1行には括弧がいらないということは良く知られているのですが(逆に、やっちゃいけないよ、って言われてるし)、でも、「,」演算子はなかなか知られておりませんw。
カンマ演算子はC言語のマクロで良く使うのですが、カンマ演算子を使うと式をつなげられるのですね。なので、if 文の後ろにある 2 行が、何故???って感覚になるのです。なるでしょう?

ちなみに、else と for の間には文が入れられません。for は式ではなくて文だからなのです。なので、意図的に書いて括弧をなくしています。

それから連想で考えたのですが、python には end if というものがない。
VB には End if とか、Next がある。
Ruby にも end がある。
SQL には end がない。
LINQ にも end がない。
LISP には、括弧が必要。

なので、終了が必要ないというのは、先の SOX のように後ろへ後ろへとコードを書くことができるんですね。このあたり、もうちょっと考察をしたら書いていきます。

カテゴリー: 雑談, C++, python | 6件のコメント

現在の通信プロトコルには層がひとつ足りない話

昨日の.NETラボの飲み会で話した「通信プロトコルに層がひとつ足りない」の話をちょっとメモ書き。

Siverlight のサーバーアクセスは WCF だったり、ASP.NET MVC からのデータベースアクセスは Entity Framework だったりする訳ですが、内部的には、TCP/IP を生のプロトコルで通しています。正確には HTTP on TCP/IP ってことで、HTTP プロトコルな訳ですが、alive http であろうと、session 毎に切ってしまう http だろうと、ちとある意味で、アプリケーション層と プロトコル層(TCP/IP層) – 用語は、正確ではないのですが — が直結しているために、データのやり取り(特に Connection や 例外関係)に無理があります。

結論から言うとですね、H さんとか、I さんとか、F さんとか、で業務アプリで通信データのやり取りをすると、必ず、TCP/IP を 2 セッションはります。

TCP/IP は、サーバー/クライアント方式ですから、

Clinet -> Server

の接続が必須なんですね。これを等価にするためには、

Client -> Server
Server <- Clinet

の2セッションが必須になるわけです。何故、2セッション必要なのか、双方向通信にする必要があるのかというと、Server 側はから、なんらかの通知をしたいとき(例外発生、異常発生時)に、Client -> Server の一方向だけだと、Client がポーリングをしていない限り、通知を受け取れないのです。つまり、Client が Get しない限り、Server から緊急通知を受けれないというタイムラグが発生します。

なので、サーバーからクライアントへの通知のために、もう1本コネクションを使います。

で、この2つのセッションですが、それぞれの会社で独自の実装をしています。と言いますか、プロジェクト単位で独自の実装をしています。まぁ、開発標準的なものもあるんですが、結局、ライブラリを使って独自の使い方になっちゃう。

これをデータベースアクセスにして考えてみると、Siverlight の非同期通信と、DB アクセスの同期通信が微妙に交差してしまうのです。

  1. Siverlight で、WPF 経由で Web サーバーをコール
  2. 結果待ちになる
  3. Web サーバーが、DB へ同期通信
  4. Web サーバーが、Silverlight へ WPF 経由で結果を返す。
  5. Silverlight が、イベントを発生させる。

という流れになっています。

Silverlight は、一見、非同期通信をしているように見えますが、データベースアクセス的に同期通信に縛られるんですね。これは、.NET Framework プログラミングの第3版を読んでいて気づいたのですが、Silverlight の通信中に他のことができるようにする、ということと(UX的にという意味で)、DB アクセスをしてデータを拾ってくるという意味とは微妙に異なります。

なので、理想的な非同期通信を書き直すと、

  1. Silverlight で、WPF 経由で Web サーバーをコール
  2. Web サーバーは WPF をキャッシュする
  3. Web サーバーは DB へ同期通信
  4. Web サーバーは WPF キャッシュを利用して、Siverlight 自身へ接続
  5. そしてデータ通信
  6. Siverlight は、イベントを発生させる。

という流れになります。一見、先の流れと同じように見えますが、4 のところで、改めて接続しているところが違います。

1 本目のセッションでは、Silverlight から Web サーバーへの WPF コール
2 本目のセッションでは、Web サーバーから Siverlight へのデータコール

になります。
こうすると、Siverlight のほうは、データ受信待ちのポーリングが必要なくなるので、動作が軽くなります。

で、本来の「セッション」の意味づけとして、等価な双方向通信として、この 2 本のセッションをまとめて「セッション」と呼ぶような層が必要、ということなのです。

擬似コードで言うとこんな感じですね。


private DualConnection _cn = new DualConnection

void Setup() {
	// イベントをセットアップ
	_cn.OnConnectin += OnConnection;
	_cn.OnRecv += OnRecv;
	_cn.OnClose += OnClose;
}
void Connect() {
	_cn = new DualConnection()
	// ホスト名を指定するが、どちらから接続してもOK
	_cn.Open( hostname );
}
void OnConnect() {
	// 相手から接続してきた場合
}
void OnRecv( byte[] data ) {
	// 受信データ
}
void OnClose() {
	// 切断処理
}

という形で定義しておいて、

  • Listen は、いらないので、いきなり OnConnection 後に OnRecv が入ってくる。
  • 送信は普通に _cn.Send のように送る。

という層をひとつ用意します。

マルチコネクションにする場合は、

void OnConnect( string hostname ) {
	// 相手から接続してきた場合
}
void OnRecv( byte[] data, string hostname ) {
	// 受信データ
}

のように、sender 要素を入れておくのも良いのですが、これだと受信側がマルチにならないので、実装的には勝手にスレッドを作成して、スレッド単位で P2P 的に接続するのがよいですね。

このあたりの実装を各社さん、それぞれが作っているので、双方向プロトコル on TCP/IP として実装されたらいいなあとか、なんとか。自分で作るか?

# P2P が似たような実装をしているはずなんですが、ちょっとコードを見たことないので分からず。

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

もう LINQ to XML はいらない(電撃戦)

NUnit の説明用に作ってみたのですが、説明にしてはコードが難しいので、こっちにのほうに公開します。
コードに関しては、たった 400 行弱の実装で、同じぐらいの長さの NUnit のコードがあります。

最初は、あまりテストファーストで作らなかったので、無駄なコードが混じっているのですが、ひとまず作ったときの手順をさらして行きますね。もうちょっとまとめたら codeplex にでも公開します。

まず、基本クラスをざっと設計してしまいます。

class EXDocument {
	XmlDocument _xmldoc ;
}
class EXElement {
	XmlElement _xmlelement ;
}
class EXElement : List<EXElement>
class EXAttr {
	XmlAttribute _xmlattr ;
}
class EXAttrs : List<EXAttr>

これだけですw 内部に XmlDocument/XmlElement を持たせて、それを参照して XPath 風に動かします。
C++ の時は、このあたりの実装も考えていたのですが、C# は面倒なので XML 関係はお任せにします。

[Test]
public void TestRoot()
{
    EXDocument doc = new EXDocument();
    doc.LoadXML(@&quot;
<members>
	<person>masuda</person>
</members>
&quot;);
    EXElement el = doc / &quot;members&quot;;
    Assert.IsNotNull(el);
    Assert.AreEqual(&quot;members&quot;, el.Name);
    Assert.AreEqual(&quot;&quot;, el.Value);

    EXElements els = doc / &quot;members&quot; / &quot;person&quot;;
    Assert.IsNotNull(els);
    Assert.AreEqual(1, els.Count);
    el = els[0];
    Assert.IsNotNull(el);
    Assert.AreEqual(&quot;person&quot;, el.Name);
    Assert.AreEqual(&quot;masuda&quot;, el.Value);
}

最初のテストケースがこれです。

EXDocument::LoadXML は、単純に XmlDocument::LoadXML を呼び出すだけです。

このあたりは【テストファースト】でもありますが、この回の場合は UI 設計も同時にはいっています。
UI 設計という言葉を使うのは、EXDocument をどのように扱うのか?どのように扱いたいのか?というインターフェースの設計だからです。

XML データを読み込んだ後は、

	// ルート要素を取得する
    EXElement el = doc / "members";

	// person 要素を取得する
    EXElements els = doc / "members" / "person";

という使い方がしたい、という(自分の)要件なのです。

さて、これをコンパイルしようとすると、まずは、「EXDocument と string で / 演算子は使って EXElement に変換できない」というコンパイルエラーがでます。

という訳で、仰せの通り EXDocument クラスに / 演算子を実装します。

public static EXElement operator /(EXDocument doc, string s)
{
    if (doc._documentElement != null)
    {
        if (doc._documentElement._xmlelement.Name == s)
        {
            return doc._documentElement;
        }
        else
        {
            return EXDocument._emptyElement;
        }
    }
    return null;
}

_documentElement を参照しているのが冗長ですが、ルート要素のタグ名と引数の文字列を比較して、マッチしたらルート要素を返す。マッチしなかったら空の要素を返す、ってことにしています。

# 空の要素を返すのは、扱いが便利になる null object パターン(empty object パターン?)です。
# null ポインタを返してエラーにするよりも、何もしないものをさらっと返すほうが、呼び出し側のコードが短くなります。

これだけのコードで、

EXElement el = doc / “members”;

の部分は通ってしまいます。

更に、もうひとつの要件をクリアすためにコンパイルエラーを見ます。
「EXElement と string の / 演算子で、EXElements に変換できない」というコンパイルエラーです。

これも先のコードと同じように EXElement クラスに / 演算子を追加します。

public static EXElements operator /(EXElement el, string tag)
{
    EXElements els = new EXElements();
    foreach ( XmlNode nd in el._xmlelement.ChildNodes ) 
    {
        XmlElement xl = nd as XmlElement;
        if ( xl != null ) {
            if ( xl.Name == tag ) {
                EXElement ne =  el._document.CreateElement();
                ne._xmlelement = xl;
                els.Add(ne);
            }
        }
    }
    return els;
}

ややこしいそうですが、やっていることは大したことはありません。
対応する XmlElement の子要素に対してタグ名にマッチするものをコレクションしているだけです。コレクションがばんばん作られますが、まぁ、中身の XmlElement オブジェクトはポインタとして参照するので、メモリ的には問題ないでしょう。

こんな風にすると、さっくりと、下記の2つのコードがコンパイルできるようになります。

	// ルート要素を取得する
    EXElement el = doc / "members";

	// person 要素を取得する
    EXElements els = doc / "members" / "person";

お次は、EXElement とか EXElements のままだと使いづらいので、string に直接代入できるようにします。

カテゴリー: C#, xUnit | もう LINQ to XML はいらない(電撃戦) はコメントを受け付けていません

もう LINQ to XML はいらない(前哨戦)

昔、10年ぐらい前だったか C++ でこんなアイデアを思いつきました。

<members>
 <person name='masuda' age='40'>masuda tomoaki</person>
 <person name='yamada' age='20'>yamada taro</person>
</members>

こんな風な XML があったときに、

XmlElement *el = doc/members/person@name == "masuda";

のように、XPath 風にデータを取得できたら楽だろう、と思ったわけです。
実際は、members や person は、文字列になるので、

XmlElement *el = doc/"members"/"person"@"name" == "masuda";

な感じでコンパイルが通らないかなぁ、と。これをどうやって実現するかというと、【演算子】のオーバーロード機能を使います。
/ 演算子をオーバーライドして、

list<XmlElement*> operator / ( list<XmlElement*> *els, string )
{
 ...
}

のように演算子の多重定義すればできるかなぁ、と。それで、10 年越しに C# で実現してみました。
残念ながら @ 演算子がないので、% 演算子で代用して、

EXElement el = doc/"members"/"person"%"name" == "masuda";

とすると、name 属性の値の要素が取れます。
更に言えば、

string val = doc/"members"/"person"%"name" == "masuda";

のように string 型の変数に代入することで自動的に “masuda tomoaki” が取れるようになります。
このあたりの自動キャストは implicit で暗黙のキャストを使います。普段はキャストを暗黙にすると問題が発生しそうでやめておくのですが、こんな風に LINQ っぽく書く(あるいは関数言語っぽい書き方)をするおきは、自動キャストをうまく考えておくと、処理する行が短くなります。

# ちなみに == も演算子の多重定義をして、EXElements を返す処理にしていますw

そんな訳で、C# で次のコードを動かせるようにしました。

// person タグをコレクションで取得
EXElements els = doc / &quot;members&quot; / &quot;person&quot;;

// ひとつしかないと分かっていれば、単数で取得
EXElements el = doc / &quot;members&quot; / &quot;person&quot;;

// どうせだから、直接、文字列に変換してしまう。
string[] vals = doc / &quot;members&quot; / &quot;person&quot;;
string val = doc / &quot;members&quot; / &quot;person&quot;;

// 比較演算子を使って、マッチングもできる
EXElements els = doc / &quot;members&quot; / &quot;person&quot; % &quot;name&quot; == &quot;masuda&quot;;

// 複数の属性で検索したい場合は、ラムダ式を使う。
EXElements els = (doc / &quot;members&quot; / &quot;person&quot;).Find( m => m % &quot;name&quot; == &quot;masuda&quot; && m % &quot;age&quot; == &quot;40&quot; )

// 子孫を検索するときは、* 演算子を使う.
EXElements els = doc * &quot;members&quot; / &quot;person&quot; % &quot;name&quot; == &quot;masuda&quot;;

こんな感じで、なにやら不思議なものができたので、後でアップします。
ええ、当然のごとく NUnit を使ってテストをしています。と言いますか、この手の複雑なロジックは NUnit を使わないと仕上がりません。

カテゴリー: 開発, C# | もう LINQ to XML はいらない(前哨戦) はコメントを受け付けていません