Hatena::ブログ(Diary)

当面C#と.NETな記録 このページをアンテナに追加 RSSフィード

2007/9/20 (木)

[] そんなエサに…  そんなエサに…を含むブックマーク  そんなエサに…のブックマークコメント

http://jibun.atmarkit.co.jp/lskill01/rensai/algo01/algo01.html

+1しかできないコンピュータ

 int add(int a,int b){
        int ans = a;
        while(b){
                ans++;
                b--;
        }
        return(ans);
}

「b--;」?

トラックバック - http://d.hatena.ne.jp/siokoshou/20070920

2007/9/18 (火)

[] しょぼい高速化  しょぼい高速化を含むブックマーク  しょぼい高速化のブックマークコメント

string.Format() は string の連結より遅いことがある。自分メモなのでマイクロベンチコードは省略。

ご利用は自己責任でドゾー。

トラックバック - http://d.hatena.ne.jp/siokoshou/20070918

2007/9/14 (金)

[] .NETにお手軽並列化がやってきた  .NETにお手軽並列化がやってきたを含むブックマーク  .NETにお手軽並列化がやってきたのブックマークコメント

今月のMSDNマガジンより。.NET3.5 にこんな隠し玉が!.NETに興味がないけど並列化に興味がある人にもおすすめ。

http://msdn.microsoft.com/msdnmag/issues/07/10/Futures/default.aspx?loc=jp

イミフなところもあるけど、とてもおもしろい記事です。

実行時の環境にあわせてスレッド数を動的に調整したり、遊んでいるプロセッサがないように動的に処理を分散したりしてくれるそうな。スゴー。

名前は Parallel FX Library の Task Parallel Library (TPL) だそうで。id:siokoshou:20070508 で書いた OpenMP チックな並列実行が .NET3.5 に入るみたい。実行するマシンがシングルコアなら普通に順次実行して、複数コアなら作業負荷に応じて並列で実行だって。制御文はデリゲートを引数に取る仕組みで、どこかの言語みたい。

従来のスレッドより簡単に使えて、かつ、実行時のプロセッサの数や状況に応じて処理を分散してくれるっつーのはいいですねぇ。並列ソートはすぐにも使えそう。こういう並列化がうまくハマル画像処理とかそういったモノには強力かと。はまらないものにも Parallel.Do とか フューチャ っていうのでがんばって手助けしてくれるようです。

Work-stealing (ワーク スティーリング)という方法で作業負荷を「動的に分散」するんだそうな。おもしろい。今はこんなに難しいよって例として挙げてる、図1はすごいなぁ。でもこれより高度なことしてくれるんですねぇ。

[] LINQ でパーサ  LINQ でパーサを含むブックマーク  LINQ でパーサのブックマークコメント

↑の続き。TPL の記事で前に紹介した LukeH さんのレイトレがサンプルに使われてます(釣りかと思ったw ってそれは自意識過剰かw)。レイトレもスゴーだけど、最新作はもっとワケワカで、LINQ で MiniML のパーサを書いてます。なんで LINQ でパーサ? LINQ って SQL もどきだよね?とか、さっぱりついていけないけど、Erik Meijer さんの論文なんかにリンクしてあるところをみると、計算機科学に詳しい人にはおもしろいサンプルなのかも。

NyaRuRuNyaRuRu 2007/09/14 16:47 >MiniML のパーサ
TechEd のときに波村さんに教えてもらいました.波村さん曰く Luke さんは「LINQ to SQL が大嫌いで LINQ to Object が大好きな人」だとか.
私も LINQ to Object 好き好きなので,一回ご挨拶したいところ.

siokoshousiokoshou 2007/09/14 18:32 おもしろい人ですねw スーパーハカーにとってはデータベースなんてお仕事臭くて嫌いなのかなw
私も LINQ to SQL が一番使われるだろうなと思いつつ、LINQ to Object のパズルっぽい楽しさに魅了されまくりです。

トラックバック - http://d.hatena.ne.jp/siokoshou/20070914

2007/9/13 (木)

[] コマンドプロンプトに電卓があった  コマンドプロンプトに電卓があったを含むブックマーク  コマンドプロンプトに電卓があったのブックマークコメント

その名は set /a。

C:\>set /a 5*3
15
C:\>set /a (5+3)*8
64
C:\>set /a 0x10*2
32
C:\>set /a "2<<2"
8
C:\>set /a 4294967295
-1
C:\>set /a 4294967295+1
0

シフトは「"」で囲ってやれば使える。その他詳しくは set /? で。

知らなかった〜。

トラックバック - http://d.hatena.ne.jp/siokoshou/20070913

2007/9/9 (日)

[] テンプレートメソッドパターンと高階関数  テンプレートメソッドパターンと高階関数を含むブックマーク  テンプレートメソッドパターンと高階関数のブックマークコメント

最近↑の本にお熱です。だいぶ前に本屋で見かけたときは変な本だなと思って買わなかったんだけど、その後あちこちの blog で絶賛してるのを見て気になってました。そしたら、近所の図書館にあったんで、ちらっと読んでそのままずっぽりはまってます。デザパタ本は何冊か持ってて、そしていつも途中で読み飽きてたけど、この本はおもしろい!自分にはあってるようです。お馬鹿っぽい本に見えて、実は濃いです。そういう本ってかなり好き。でも誤りがちょい多かったり、訳がイミフなところがあったり…。

で、この本の中で、Sort( IComparer<T> comparer ) みたいなのをテンプレートメソッドパターンの変種だ、と面白いことが書いてありました。

教科書通りのテンプレートメソッドパターンだと、アルゴリズムの大枠を基本クラスで用意して、変化する部分だけを子クラスのメソッドに実装させます。WinForm とかの GUI をはじめ、フレームワークって名前で呼ばれるようなものにはホントによく使われるパターンですね。あちこちで出会うパターンです。

Sort の話に戻って、比較処理を外に出してる点がテンプレートメソッドパターンの精神を持っているそうな。う〜ん、そう言われてみれば根っこの考え方は同じですね。で、「それって高階関数」と思ったんだけど、これはつまり、テンプレートメソッドパターンと高階関数の考え方の根っこは一緒ってことか!とエウレカ体験。

教科書通りなら関数を渡す変わりに継承を使うけど、継承を使って関数を渡してると考えれば同じようなもんですねぇ。

この本の最初に出てくる原則「変化する部分をカプセル化して、変化しない部分と分離する」にしっかり当てはまるパターンだけど、これはそのまま高階関数にも言えることですよね。ついでに言えば、どちらも DRY 原則をきっちり守ってます。関数型言語は DRY 原則に過剰なまでに従っているけどw

オブジェクト指向的にやってしまうのがテンプレートパターン。つまり Sort( IComparer<T> comparer )。関数型言語風にやってしまうのが高階関数。つまり Sort( Comparison<T> comparison )。

Closure ぽんと渡しておしまいか、インターフェイスを用意しておいて、それをインプリしたインターフェイスを渡すかの違いはあるけど、根っこは一緒と。

まとめると、高階関数をオブジェクト指向風にやるのがテンプレートメソッドパターンと。ちょっと変わった理解の仕方をしてしまったけど、意外なところで意外なものが繋がりだして、なんだかおもしろい。

そうそう、この本のいいところは、デザパタを使いすぎるなってことがちゃんと書いてあるところ。激同なのでちゃんと書いてあることがうれしい。

トラックバック - http://d.hatena.ne.jp/siokoshou/20070909

2007/9/7 (金)

[] 親クラスのメソッドを隠す  親クラスのメソッドを隠すを含むブックマーク  親クラスのメソッドを隠すのブックマークコメント

id:siokoshou:20070901#p2id:siokoshou:20070903 の補足やらなにやらをつらつらだらだらと。


反変

id:siokoshou:20070901#p2 で書いた例は、オブジェクト指向に詳しい方なら「それって反変」とピンと来たと思います。オブジェクト指向のややこしぃ話に「共変(covariant)と反変(contravariant)」ってのがあって、Method( string )/Method( object ) の例はその反変の例になっています。前回の答えのエントリでは、親のメソッドを隠してしまうことをわりと否定的なニュアンスで書きましたが、わざと便利に使うこともできます。だからこそコンパイラは警告も出さないんでしょう、たぶん。難しい話はよくわからないので檜山さんによる詳しい説明をドゾー。牛スキーにはたまらないお話です(^^;

あれ?この説明読むともしかしてこういう動きの言語のほうが普通なのかな…?

オブジェクト指向は便利に使えているうちは好きですが、こういうややこしぃお話は避けて通ってます、ハイ。MSDNライブラリを共変とか反変でキーワード検索するとデリゲートとジェネリックが引っかかって興味深いお話が載ってたりします。ほかに配列の共変性なんてのもあります。ちなみに共変のオーバーロードは特におもしろいことも何もなく、普通に使えます。

ところで、short/int の例は共変とか反変とか言うんでしょうか?継承関係はないけれど、暗黙の変換はあるという例でしたけど。共変と反変の詳しい定義がわかりません…。


オーバーロードか隠蔽か?

id:siokoshou:20070903 では注意してこれらの用語を使わなかったんですが、どっちなのかよくわからなかったからだったりします(まぁどっちでもいいんだけどw)。C# コンパイラにしてみればオーバーロードなんだろうけど、意味的には「隠蔽」ですよね。C# ではシグネチャが一致した隠蔽の場合はコンパイル時に警告が出るので、警告を消すには new 修飾子を付けますね。

先の2例ではコンパイラは何も言わないけど、親のメソッドが見えなくなるので隠蔽にあたると思うんですけどねぇ。コンパイラが警告出したほうが親切じゃね?とか思うのは過剰な期待でしょうか…。


FxCopで検出できるか?

FxCopは大げさだし、しょうもない警告をいっぱい出して重要な警告が埋もれてしまうので嫌いなんですが、まぁ使ってみました(lint もどきはいらないから、gcc -Wall もどきが欲しい!)。

string/object の例は検出できました。Design Rules/Do not hide base class methods ルールです。CA1061。でも、short/int の例は検出できず。

おそらく継承関係があれば検出できるけど、継承関係がなくて暗黙の変換による隠蔽の場合は検出できないんだと思います。そんなにいろいろ試したわけじゃないので、多分に推測を含みますが。


この事実は有名?

C#の仕様書は参考とか例が豊富ですが、JISの仕様書をざっと見た限りでは触れてなさげです。リッチャー本でも触れてなさげ。関係ないけど id:siokoshou:20070901#1 はリッチャー本におもいっきり書いてありました…。NULL チェックが不要なときの例はさすがに載ってなかったけど。

FxCop でも検出が中途半端だし、もしかして、あまり知られていないのかも?


わかっててわざと使うんだったらOKと思いますが、ついついこの落とし穴に落ちないためにはオーバーロードの濫用を控えるってのが有効な手というところでしょう。

トラックバック - http://d.hatena.ne.jp/siokoshou/20070907

2007/9/3 (月)

[] C#クイズの答え  C#クイズの答えを含むブックマーク  C#クイズの答えのブックマークコメント

id:siokoshou:20070901#2 のクイズの答え。問題をまだ見てなければ、先に問題を見てからどうぞ。

実行するとこうなります。単純なコードに見えるけどクイズにするくらいなので、意外なほうが呼ばれます。

Derived.Method(string)
Derived.Method(object)
Hoge.Method(string)

1つめと3つめはフツー(比較のためにやってみただけ)、2つめが 工工エエエエ(´Д`)エエエエ工工

なんでこうなるんだか調べてるうちにもっと簡単な例を見つけたので、なんで?って話の前にそちらを。

using System;

public class A
{
    public void F( short s )
    {
        Console.WriteLine( "short" );
    }
}

public class B : A
{
    public void F( int i )
    {
        Console.WriteLine( "int" );
    }
}

public class Program
{
    public static void Main()
    {
        short val = 15;

        B b = new B();
        b.F( val );

        Console.ReadKey();
    }
}

これもエエーってほうの int が表示されます。きっとこんな言語はほかにないかも?

どのメソッドを呼ぶか決めるルールは、まずはそのクラスのメソッドから当てはまるものを探して、そこで見つかればそれでおしまい。見つからなかったときに初めて次のベースクラスを探す、って決まりなんだそうな。

short から int への暗黙の変換があるので、この例では short を引数にして呼んだのに、B.F( int ) が呼ばれてしまいます。

この例は ここ で見つけました。解説はこっち。死にそうなくらいお暇なら JISの仕様書 14.5.5.1 の備考とか、そのあたりもどうぞ。

で。仕様はわかったけど、なんで?ってところですよね。これも説明があって、バージョン管理のためにこうなっているそうな。バージョン管理は C# の特徴的な機能で、Java を改良した点の一つですね。C# はまだ若いので今はまだこの機能はたいして意識されないけど、そのうちじわじわ利いてきます、たぶん。

A クラスと B クラスを別の人が開発してたとして、A の最初のバージョンには A.F( short ) がなかったとします。このとき、誰かが B.F( int ) を使ってたとします。short で呼ぶなよってのはおいといて。で、後のバージョンで A.F( short ) が追加されたとします。でも、C# のルールだと B.F( int ) を使ってた人はやっぱり B.F( int ) をそのまま呼び続けることができます。めでたし!ってわけです。

理由を聞くとよく考えてあるなぁって思いますねぇ。

で、こないだのクイズに戻ってみると、この例とは override の部分が違います。C# の仕様書によれば override したメソッドは探し出す候補から外されます!最初はなんで?って思ったけど、考えてみれば一緒ですね。後からベースクラスに Base.Method( string ) が追加されて、ベースクラスに追加されたからこそ派生クラスでオーバーライドできるわけなので。

つまり、

1.最初は Base はメソッドなし。派生には Derived.Method( object ) があって、誰かがそれを利用してる。

2.Base.Method( string ) が追加された。でも Derived.Method( object ) を呼んでる人には影響なし。

3.Derived.Method( string ) としてオーバーライド追加。でもやっぱり Derived.Method( object ) を呼んでる人には影響なし。

って流れ。

どう思いますか、この仕組み?バージョン管理は必要かもしれないけど、それにしても見事な落とし穴って感じ。

クイズのネタ元はこちらでした。via http://blogs.msdn.com/nealho/archive/2006/01/19/515173.aspx

GushwellGushwell 2007/09/04 09:24 メソッドのオーバーロードに、こんな落とし穴があったとは...
こういったコードを書いちゃうと、どのメソッドが呼ばれているのかさっぱり
分からなくなりそうなので、自分では書かないと思うけど。

siokoshousiokoshou 2007/09/04 10:18 でもこれ、ついうっかり書いてしまいそうで怖いですよねぇ。

トラックバック - http://d.hatena.ne.jp/siokoshou/20070903

2007/9/1 (土)

[][] call と callvirt その5  call と callvirt その5を含むブックマーク  call と callvirt その5のブックマークコメント

5月の記事の続き。続きを書く日が来るとは自分でも驚き。IL のお話です。

インスタンスメソッドを呼ぶときにコンパイラが call を生成したり、callvirt を生成したりします。その違いは何よ?とずっと疑問だったんですが、その答えが!

vir http://blogs.msdn.com/ericlippert/archive/2007/08/17/subtleties-of-c-il-codegen.aspx

インスタンスの NULL チェックが不要なときは call だそうな。逆に NULL チェックを強制したいときが callvirt。NULL チェックの奇妙な機械語の件が The Old New Thing で取り上げられています。

NULL チェックが不要なときの例 : (new Foo()).FooNonVirtualMethod()

ちょっと実験。

using System;

class Program
{
    static void Main()
    {
        Hoge hoge = new Hoge();
        Console.WriteLine( hoge.Huga() );
        Console.WriteLine( new Hoge().Huga() );
    }
}

public class Hoge
{
    public string Huga() { return "HogeHuga"; }
}

IL。Main だけ。

.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // コード サイズ       33 (0x21)
  .maxstack  1
  .locals init ([0] class Hoge hoge)
  IL_0000:  newobj     instance void Hoge::.ctor()
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  callvirt   instance string Hoge::Huga()
  IL_000c:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0011:  newobj     instance void Hoge::.ctor()
  IL_0016:  call       instance string Hoge::Huga()
  IL_001b:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0020:  ret
} // end of method Program::Main

IL_0007 は callvirt ですが、IL_0016 は確かに call になっています。

へぇなトリビアですね。

ちなみにエリックさんの同じエントリでC#コンパイラのバグでスレッドのデッドロックに至る可能性があるバグが告白されていたり。3.0でも健在だって。

[] C#クイズ  C#クイズを含むブックマーク  C#クイズのブックマークコメント

実行結果を予想してください。答えは後日。

using System;

public class Program
{
    public static void Main()
    {
        Base b = new Derived();
        Console.WriteLine( b.Method( "dummy" ) );    // (1)

        Derived d = new Derived();
        Console.WriteLine( d.Method( "dummy" ) );    // (2)

        Hoge hoge = new Hoge();
        Console.WriteLine( hoge.Method( "dummy" ) ); // (3)

        Console.ReadKey();
    }
}

public class Base
{
    public virtual string Method( string s )
    {
        return "Base.Method(string)";
    }
}

public class Derived : Base
{
    public override string Method( string s )
    {
        return "Derived.Method(string)";
    }

    public virtual string Method( object o )
    {
        return "Derived.Method(object)";
    }
}

public class Hoge
{
    public string Method( string s )
    {
        return "Hoge.Method(string)";
    }

    public string Method( object o )
    {
        return "Hoge.Method(object)";
    }
}

NyaRuRuNyaRuRu 2007/09/02 13:30 >C#コンパイラのバグ

個人的な意見ですが,コンパイラのバグと言うよりは,CLRとBCLで配慮が足りなかった部分をコンパイラに押しつけているようにみえますなぁ.
http://d.hatena.ne.jp/NyaRuRu/20060605

ローカル変数への代入とメソッド呼び出しの順序について,通常は 1)メソッド呼び出し 2)ローカル変数への代入 ですが,lock や using の場面でこの順序を反転させる必要があることを,CLR や BCL の人たちがちゃんと把握していたのかちょっと怪しいと思っています.

siokoshousiokoshou 2007/09/03 01:33 なるほど〜、押し付けあっていつまでも直らないってありがちな構図かもしれませんねぇ。
そして、usingも解放漏れするんですか(´・ω・`)

2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 06 | 09 | 11 | 12 |
2007 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 08 | 09 | 10 | 12 |
2009 | 01 | 03 | 04 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 07 |
2011 | 04 | 07 | 10 |
2012 | 04 | 12 |
2013 | 08 |
2014 | 03 | 08 |
2017 | 09 |