Daigo Hamura's Weblog

  • 最終出社日

    ご連絡が遅くなりましたが、本日を最終出社日としてMicrosoftを退職することになりました。

     

    Microsoftの社員として、そして一エンジニアをして皆様とご一緒し、仕事のみならず、

    さまざまな面で成長することができました。心から感謝しています。

    今後は皆様と同じく、Microsoft をカスタマーの立場から応援、サポートしていきたいと思っています。 

     

    皆様とは、また別の機会にご一緒できることを願っています。

    これまで本当にありがとうございました。

     

    波村大悟

  • Developers Summit Demo Script – Intermission

    MIX 08 のあと急に本業が忙しくなってしまい更新が遅れてしまいました。

    言い訳になりますが、MIXのような大きな発表のあとはFeedbackとバグレポート、またFeedback

    を取り入れるための Design Changes が毎日10 件ほど。

     

    デブサミ シリーズも半分終わりましたがあと5 Parts 残っています。。。

    -          Join (Part VI)

    -          Linq to SQL (Part VII)

    -          Linq Data Source (Part VIII)

    -          ASP.NET Dynamic (Part IX)

    -          Summary (Part X)

    来週にでも、終わらせたいと思います。

     

    で、今日は少しだけ脱線して、Intermission  です。

     

    前回までのシリーズで、C# 3.0 では宣言的にかけるようになったとか、シンタックスが綺麗になったと紹介した数々の新機能は、実は必要に応じてデザインした結果そうなったのが多数をしめています。Presentation Blog ではデザインの段階から決めてそうなったような言い方をしますが、本当の言語のデザインは泥臭いものです。 

     

    微分と積分の関係はニュートンが両者がある意味で逆の関係にあることを見抜くまでは別の分野として研究されていたように、言語のデザインにおいても「発見と帰納」「仮説と演繹」の両方で成り立っています。もちろん、シッカリした方向性やヴィジョン的なものが根底にあるからこそ成り立つともいえます。

     

    例えば、Part I にて紹介したローカル変数の型推論  var Part V にでてきた匿名型 -  Anonymous Typeをサポートするために取り入れた機能ですが、使ってみると便利なので、C# 3.0 の代表的な機能の一つとして紹介するのです。もう一つの例としては、Part II で紹介したオブジェク イニシャライです。 現時点でのLINQ はすべて Expression で表現できるものに対して使える構文です。 Expression Statement の違いは

     

    Statement

                    if (x) { x = false; } else { x = true; }  // if statement

     

    Expression

                    x = x ? false : true ; // conditional expression

     

    のように、同じ事をするのにも Expression 的な書き方と Statement 的な書き方両方あります。C# 2.0 までは Expression 的に object を初期化する方法がなく、LINQ をサポートするために言語仕様を変更したところ、宣言的にかける事に気づきいたというのが本当のところです。 

     

    長々と、書いてしまいましたが、今日のメインポイントは言語設計は泥臭いということを伝えたかったのです。

     

    次回は、Join (Part VI) です。Stay Tuned!

  • Developers Summit Demo Script – Part V

    今回は ‘Linq to XML’ を使ってデータをXML から取り出したあと、前回と同じクエリを投げてみます。

     

    最初に、少しだけ Prep Workここから、Product.xmlをダウンロードして保存してください。保存したパスはあとで使いますので、覚えておいてください ここでは”C:\data\Product.xml”とします。

     

    次に、Default.aspx.csファイルの中のGetProductList() メソッドを以下のコードに置き換えてください。もともとのGetProductList()List<Product>をメソッドの中で初期化していました。今回は、同一のデータをproduct.xmlの中から ‘Linq to XML’を使って取り出してきています。

     

            List<Product> GetProductList()

            {

     

                var query =

                    from e in XElement.Load(@"C:\Data\product.xml").Elements("Product")

                    select new Product()

                    {

                        ProductID = (int)e.Element("ProductID"),

                        CategoryID = (int)e.Element("CategoryID"),

                        ProductName = (string)e.Element("ProductName"),

                        UnitPrice = (decimal)e.Element("UnitPrice")

                    };

     

                return query.ToList();

            }

     

    ここでもLINQ のクエリがでてきます。同じことをC# 2.0 で書くと

           

    List<Product> query = new List<Product>();

     

                foreach (XElement e in XElement.Load(@"C:\Data\product.xml").Elements("Product"))

                {

                    Product p = new Product();

                    p.ProductID = (int)e.Element("ProductID");

                    p.CategoryID = (int)e.Element("CategoryID");

                    p.ProductName = (string)e.Element("ProductName");

                    p.UnitPrice = (decimal)e.Element("UnitPrice");

     

                    query.Add(p);

                }

     

    になります。このようにシンプルなLINQ クエリはforeachを使って簡単に置き換えられますし、どちらがシンプルかと言うと難しいところですが、何度も書いたImperative -> Declarative (手続き型 -> 論理型) の違いに気づいていただければと思います。

     

    ここで、まだ紹介していなかったC# 3.0 の構文のひとつ、匿名型 -  Anonymous Type の説明をします。 Part IVで、 さきほど追加したグループのコンテナクラスは不要ですと書いた時点で説明はぶきましたが、匿名型を使うことにより、コンパイラが自動的に型の定義をしてくれます。シンタックスとしては

     

    C# 3.0 – 匿名型Anonymous Type

            var anonymousType = new {

                                    Hoge = 1,

                                    Foo = "Anonymous Type"

                                };

     

    C# 2.0 –型指定した例

            var concreteType = new ConcreteType()

            {

                Hoge = 1,

                Foo = "Anonymous Type"

            };

     

     

    class ConcreteType

    {

        public int Hoge;

        public string Foo;

    }

     

    匿名型を使うことにより、C# 2.0 の例にあるようなConcreteTypeをコンパイラがアセンブリの中に定義します。Deep Diveはしませんが、LINQ のクエリの中で匿名型も通常の型もselectできると覚えておいてください。

     

    クエリ内で匿名型を使った例

                var result = from p in products

                    group p by p.CategoryID into g

                    orderby g.Count() descending

                    select new //匿名型

                    {

                        CategoryID = g.Key,

                        Count    = g.Count()

                    };

     

    クエリ内で型を指定した例

                var query =

                    from e in XElement.Load(@"C:\Data\product.xml").Elements("Product")

                    select new Product() // Product型の指定

                    {

                        ProductID = (int)e.Element("ProductID"),

                        CategoryID = (int)e.Element("CategoryID"),

                        ProductName = (string)e.Element("ProductName"),

                        UnitPrice = (decimal)e.Element("UnitPrice")

                    };

  • Developers Summit Demo Script – Part IV

    ようやくLINQについて書けるときが来ました。ここまで長かった。。。地味な変更が続いたのでインパクトのあるやつをやりましょう。

     

    では、いつものようにdefault.aspx.csを開いて、void Page_Load(object sender, EventArgs e) メソッドにカーソルを移動してください。このメソッドにはまだ修正を加えていないので、オリジナルのコードが

     

    protected void Page_Load(object sender, EventArgs e)

            {

                List<Product> products = GetProductList();

     

                GridView1.DataSource = products;

                GridView1.DataBind();

            }

     

    あるはずです。では、products のデータをグループに分けてそのグループのレコードの数を計算するコードをC#2.0を使って実装してみます。

     

    まず、グループのコンテナクラスを追加します - Demo 名前空間のどこかに以下のコードをコピーしてください。

     

        class Grouping

        {

            int productCount;

            int categoryID;

     

            public int ProductCount

            {

                get { return productCount; }

                set { productCount = value; }

            }

     

            public int CategoryID

            {

                get { return categoryID; }

                set { categoryID = value; }

            }

        }

     

    次に、実際にグループ化するロジックを Page_Load  メソッドの中に追加。

     

            protected void Page_Load(object sender, EventArgs e)

            {

                List<Product> products = GetProductList();

     

                Dictionary<int, Grouping> groups = new Dictionary<int, Grouping>();

                foreach (Product p in products)

                {

                    if (!groups.ContainsKey(p.CategoryID))

                    {

                        Grouping r = new Grouping();

                        r.CategoryID = p.CategoryID;

                        r.ProductCount = 0;

                        groups.Add(r.CategoryID, r);

                    }

                    groups[p.CategoryID].ProductCount++;

     

                }

     

                List<Grouping> result = new List<Grouping>(groups.Values);

          GridView1.DataSource = result;

                GridView1.DataBind();

            }

     

    ここまでのコードをミスなく書ける人はそれなりにいるかもしれません。では、さらにソートを追加してみましょう。

     

              

              

     

    List<Grouping> result = new List<Grouping>(groups.Values);

                result.Sort(delegate(Grouping x, Grouping y)

                    {

                        return

                            x.ProductCount > y.ProductCount ? -1 :

                            x.ProductCount == y.ProductCount ? 1 :

                            0;

     

                    }

                );

     

                GridView1.DataSource = result;

              

              

     

    ここまで一つのバグを入れることなく書けた人はすばらしい。でも、本人が書けたとしてもそれをほかの人が読んですぐ理解できるかというと?です。

     

    そこで、LINQの登場です。結論から言うと、LINQを使ったコードは

     

            protected void Page_Load(object sender, EventArgs e)

            {

                List<Product> products = GetProductList();

               

                var result = from p in products

                    group p by p.CategoryID into g

                    orderby g.Count() descending

                    select new

                    {

                        CategoryID = g.Key,

                        Count    = g.Count()

                    };

     

                GridView1.DataSource = result;

                GridView1.DataBind();

            }

     

    しかも、さきほど追加したグループのコンテナクラスは不要です。比べていただくを分かりやすいのでC# 2.0 Based

     

           protected void Page_Load(object sender, EventArgs e)

            {

                List<Product> products = GetProductList();

     

                Dictionary<int, Grouping> groups = new Dictionary<int, Grouping>();

                foreach (Product p in products)

                {

                    if (!groups.ContainsKey(p.CategoryID))

                    {

                        Grouping r = new Grouping();

                        r.CategoryID = p.CategoryID;

                        r.ProductCount = 0;

                        groups.Add(r.CategoryID, r);

                    }

                    groups[p.CategoryID].ProductCount++;

     

                }

     

                List<Grouping> result = new List<Grouping>(groups.Values);

                result.Sort(delegate(Grouping x, Grouping y)

                    {

                        return

                            x.ProductCount > y.ProductCount ? -1 :

                            x.ProductCount == y.ProductCount ? 1 :

                            0;

     

                    }

                );

     

                GridView1.DataSource = result;

                GridView1.DataBind();

            }

     

    これがLINQC# 3.0 の本質つまりPPT P7 の2つ目のポイント

     

    手続き型 à 論理型

     

    の具体的な例です。関数型言語は当たり前の、Developer がどうするのか、つまりHow に時間を使うことなく何をしたいのか、つまり What に集中することが LINQ C#3.0 を使っていただくとできるようになります。

     

    あすは、Deep に掘り下げてきた LINQ + C# 3.0 を横に広げて Linq Family を使って色々な data source にクエリをかけてみたいと思います。

  • Developers Summit Demo Script – Part III

    今回ですでにPart IIIとなるデブサミ スクリプトシリーズです。今日は自動実装 プロパティです。

     

    C# 3.0 のデザイン最終段階で追加されたこの新しい構文は、デブサミでも触れましたが、v1 の頃からの Feedback の一つです。予想したよりも反響が大きく多くのお客さんに喜んでいただけたこと、また何でこんな事ができないんだという嬉しい Feedback もいただいています。C# のデザイン哲学、keep it simple!  Simpleな事はエレガントであり理解しやすい、と同時に機能を付け足すのは簡単でも取り除くのは不可能だからです。このような言語のデザインの裏話を書いても楽しいのですが、本題のほうに戻ります。

     

    C# 2.0 のコード

    public class Product

    {

        private int productID;

        public int ProductID

        {

            get { return productID; }

            set { productID = value; }

        }

         

    }

     

    C# 3.0 を使って書き換えると。

    public class Product

    {

        public int ProductID { get; set; }

     

    }

    違いとしては、productIDfieldget/setbodyがセミコロンに置き換わっています。

     

    いつものようにここで、サンプルを修正してもいいのですが、今日はちょっとアカデミックにグラマーを見てみましょう。C# 3.0 の言語仕様によると、

    property-declaration:
    attributesopt   property-modifiersopt   type   member-name  
    {   accessor-declarations   }

    ここで重要なのはaccessor-declarations   でグラマーは

    accessor-declarations:
    get-accessor-declaration   set-accessor-declarationopt
    set-accessor-declaration   get-accessor-declarationopt

    get-accessor-declaration:
    attributesopt   accessor-modifieropt    
    get   accessor-body

    set-accessor-declaration:
    attributesopt   accessor-modifieropt  
    set   accessor-body

    accessor-modifier:
    protected
    internal
    private
    protected
       internal
    internal
       protected

    accessor-body:
    block
    ;

    じつは、グラマーはC# 2.0 から修正はまったくありません。これは、あるセッションで話した互換性の問題と深く関連していて、このように言語仕様の隙間を見つけて、Semanticの修正のみ(Parser には手を入れない)で新たな機能を付け加えることは多くあります。

     

    では、デモコードに戻り、いつもの様にdefault.aspx.csを開いてpublic class Product を以下のコードに書き換えてください。

    public class Product

    {

        public int ProductID { get; set; }

        public int CategoryID { get; set; }

        public string ProductName { get; set; }

        public decimal UnitPrice { get; set; }

    }

     

    F5で前回までの変更と今日の修正が実行できることを確認してください。これまで3回の変更でコードのreadabilityがかなり向上したかと思います。明日からは、LINQを使ってQueryをかけていきます。

     

  • Developers Summit Demo Script – Part II

    前回のBlog Post - Developers Summit Demo Script – Part Iでは、プロジェクトのセットアップとC# 3.0の新しい構文のひとつローカル変数の型推論を紹介しました。今回は、前回のコードをもとに、更に変更をくわえていきます。 今回、紹介する機能はオブジェクト イニシャライザです

     

    まず、前回使用したプロジェクトをVS2008で開いてください。 つぎに、default.aspx.csをエディタで開きGetProductList()メソッドにカーソルを移動してください。

     

    C#2.0 &  昨日までの変更

     

      var productList = new List<Product>();

            productList.Add(new Product(1, 1, "Chai", 18.0000M));

            productList.Add(new Product(2, 1, "Chang", 19.0000M));

     

    をC# 3.0 オブジェクト イニシャライザ構文を使って、書き換えると

     

    var productList = new List<Product> {

    new Product { ProductID = 1, CategoryID = 1, ProductName = "Chai"  , UnitPrice=18.0000M },

    new Product { ProductID = 2, CategoryID = 1, ProductName = "Chang" , UnitPrice=19.0000M },

          … 

    //残りのコードはここからダウンロードしてGetProductList()メソッドを置き換えてください

     

    Product(1, 1, "Chai", 18.0000M) が new Product { ProductID = 1, CategoryID = 1, …} に変わりました。

     

    まず、詳しくコンパイラの視点から見てみます。コンパイル時にコンパイラがチェックできるのは型の整合性だけです。 例えば、C#2.0

    Product(1, 1, "Chai", 18.0000M) を Product("1", 1, "Chai", 18.0000M)

    と書いた場合コンパイラは string->int の型変換ができませんので、Syntaxエラーとなります。 

     

    次に、Productクラスのコンストラクタを見てください。

     

        public Product(int productID, int categoryID, string productName, decimal unitPrice){ ...  }

     

    当たり前のことですが、引数の順番は重要で、引数が意味を持ち、その順番を間違えると実行時のエラーつまりBugの原因になります。 例えば、

    new Product(2, 1, "Chang", 19.0000M) と書くところを productID catetoryID を間違って

    new Product(1, 2, "Chang", 19.0000M) としたとします。 

    このコードはSyntax的には正しいですのでコンパイルも問題なく通り、実行することができます。  しかし、実行時の結果は予期しなかったものになります。  C# 3.0オブジェクト イニシャライザ構文を使っていただくことにより、もちろん同様の間違えをすることは可能ですが、どのメンバを初期化しているのかを明示できる、よってエラーの原因を減らすことにつながります。

    new Product { ProductID = 1, CategoryID = 1, ProductName = "Chai"  , UnitPrice=18.0000M },

    new Product { ProductID = 2, CategoryID = 1, ProductName = "Chang" , UnitPrice=19.0000M }, 

    同じようにDebugまたは保守時のストを削減できることができると思います。

     

    まとめとして、コードを書いた人が何をやろうとしているのかがより分かりやすくなりました。 これは、C# 3.0 の開発コンセプトのいかに簡潔に宣言的にコードを書けるかに沿っています。 コンストラクタの引数の順位も気にせずに明示的にメンバの名前でオブジェクトを初期化をできますので、Potential Bugを開発時に食い止めることができるようになります。

     

    次回は自動実装 プロパティの予定です。

     

     

    注: 今回のコードの修正のあとコンパイルするとエラーがでます。エラーを回避するにはProductクラスにDefaultコンストラクタを追加してください

  • Developers Summit Demo Script – Part I

    時間が過ぎるのは本当に早いもので、Developers Summit から一月近く経とうとしています。サミットで使ったDemoのコードとステップ及びPPTを公開します。

     

    最初に、以下のプロジェクトをダウンロードしてください。C# 2.0 の構文を使った典型的なコードです。プロジェクトをVisual Studio 2008で開いたあとF5Web Pageが表示されることを確認して次のステップに進んでください。

    demo.zip 

    次に、default.aspx.csをエディタで開きます。

     

    List<Product> GetProductList(){

     

    GetProductList メソッドにカーソルを移動し

     

    List<Product> productList = new List<Product>();

     

    C# 3.0 で追加されたローカル変数の型推論の構文を使って以下のように書き換えます。

     

    var productList = new List<Product>();

     

    var を使うことにより、ローカル変数 productList の型の宣言を省略することができます。もちろん

     

    for (var i = 0; i < 10; i++) { ... }

     

    のような使い方も可能です。

     

    これから数回に分けて、C# 3.0 + LINQ でいかに簡潔に宣言的なコードを書けるようになったかを、オリジナルのコードを修正しながら紹介していきます。

  • Labmda Expression と Anonymous Method の違い

    Expression Tree Compiler が DLINQ のどこで使われているかを書いてみたのですが、非常に分かりにくいことに気づきました。
     
    数回に分けてLINQの重要な部分を説明した後、改めてポストしてみたいと思います。

    まず最初に Lambda Expression と Anonymous Method Expression の違いについてです。

    決定的な違いとして lambda Expression は
       1. 型の推論
       2. Expression Tree
    のサポートです。 他にもありますが、この二つ違いはクエリ式においてさらに大きな違いとなってきます。

    例えは、DLINQ で以下のクエリを書きます。
       
       
    db.Log = Console.Out;
       var q1 = db.Customers.
                   
    Where(c => c.City == "London").
                   Select(c => new {c.City});
       var r1 = q1.First();

    上のクエリでDLINQがサーバに投げるSQL Queryは
       
       SELECT
    TOP 1 [t0].[City]
       
    FROM [Customers] AS [t0]
       WHERE [t0].[City] = @p0

    では、同じようなクエリを Anonymous Method を使って書いてみます。

       var
    q2 = db.Customers.
                   
    Where(delegate(Customer c) 
                      { return c.City == "London"; }).
                   Select(c => new { c.City });
       var r2 = q2.First();

    サーバに投げるSQL Queryは

       SELECT [t0].[CustomerID], [t0].[CompanyName], 
             
    [t0].[ContactName], [t0].[ContactTitle],
             
     [t0].[Address],
    [t0].[City], [t0].[Region], 
              [t0].[PostalCode], 
              [t0].[Country], [t0].[Phone], [t0].[Fax]
       FROM [Customers] AS [t0]

    もう気づかれた方もいらっしゃると思いますが、2つ目の SQL Query には WHERE がありません。

    Anonymous Method を lambda の代わりに使ったことによって 

       IEnumerable
    <T> Where<T>(this IEnumerable <T> source,
                               Func<T, bool> predicate)

    の Query Operator が

       IQueryable
    <T> Where<T>(this IQueryable<T> source,
                         Expression<Func<T, bool>> predicate)

    の代わりに使われてしまったためです。 最初に書いたように Anonymous Method は Expression に型変換ではないため IEnumerable<T> の Query Operator が Overload Resolution の解決によって選ばれます。 DLINQ は受け取った Expression Tree (without Where Operator Node) を素直に書き換えるだけです。
     
    もし、Customers Table が1000万件のレコードだったらとしたら。。。 DLINQ はまず1000万件のレコードをメモリに読み込み、メモリでクエリをかける事になってしまいます。 たぶんその前に OutOfMemoryException でアプリケーションが落ちてしまうか、DBA から Database へのアクセスをはずされる事になってしまいますのでお気をつけ下さい。 

  • Expression Tree Compiler (Expression Tree Advnaced)

    Expresion Tree は前回書いたように .NET Assembly に書き出された Data Structure です。 DLINQはその Expression Tree をもとに SQL に変換しデータベースにクエリを投げます。 しかし、アプリケーションによっては、Expression Tree をデータ として使いかつ、CLRの実行結果を知りたいときがあります。  このような時に役に立つのが、Expression Tree Compilerです。 Expression Tree を Delegate にコンパイルする事によって、通常の Delegate として Invoke できるようになります。

    Expression<Func<int, bool>> expr = x => x > 10;
    Func<int, bool> func = expr.Compile();  // Expression Tree から Delegate へコンパイル

    // Console.WriteLine(expr(1)); // Compile Time Error - cannot invoke expr
    Console
    .WriteLine(func(1));  
    Console.WriteLine(func(10));
    Console.WriteLine(func(11));

    次回は、この Expression Tree コンパイラが、実際どこに使われているかをDLINQの例をとって説明したい思います。

  • Expression Tree - Basic Edition 1

    また更新が遅くなってしまいました。   

    C# 3.0 で新しく追加された Expression Tree は 言語の中の Semantic Tree を .NET の アセンブリに書き出しデータとして扱えるようにするための機能です。  Express Tree ですから semantic tree の Node は Expression つまり式だけになります。

    Expression Tree を C# 3.0 で書き出す方法の一つは

    Expression<Func<int, bool>> filter = n => n < 5;

     ildasm.exe をIL使ってみて頂くと分かると思いますが、以下のようなコードがC#コンパイラによって生成されています。

    ...
    ...
    IL_0023:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    IL_0028:  call       class [System.Query]System.Expressions.ConstantExpression [System.Query]System.Expressions.Expression::Constant(object, class [mscorlib]System.Type)
    IL_002d:  call       class [System.Query]System.Expressions.BinaryExpression [System.Query]System.Expressions.Expression::LT(class [System.Query]System.Expressions.Expression,class [System.Query]System.Expressions.Expression)
    IL_0032:  ldc.i4.1
    IL_0033:  newarr     [System.Query]System.Expressions.ParameterExpression
    ...
    ...

    何か起こっているか? 結局はコンパイラが以下のコードを書き出していると思っていただければと思います。

    Expression<Func<int, bool>> filter = Expression.Lambda<Func<int, bool>>(

           Expression.LT( // Less Thanオペレータ

               Expression.Parameter(typeof(int), "n"), // ラムダ式のパラメタ名

                Expression.Constant(5, typeof(int))     // コンスタント式

                ),

            new ParameterExpression[] { Expression.Parameter(typeof(int), "n") }

            );

    もちろん、Lambda 式と使った時上のコードは同一の Expression Tree が作られます。

    ではなぜこの様な Data Structure が必要かというと、C# のコードがILに直接にコンパイルされた場合、言語の中のセマンティックスが失われてしまいます。 例えば上の例の中にあるLess Than オペレータは簡単な比較とジャンプのIL のオプコードを使って表現されます。  Expression Tree をつかうことによって、直接 Less Than の Node をコードから使えるようになります。 もし Expression Tree がなかった場合、DLINQ などの機能を実現するには、IL を IL Stream を使って取り出し Semantic Analysis を IL に対してしなくてはならなくなってしまいます。

    明日のトピックは Expression Tree Basic Edition 2 の予定です。

  • LINQ CTP May 2006 has been Released to the Web

    LINQ CTP (May 2006) がリリースされました。 こちらからダウンロードできます。

    今日から、やっと普通の生活に戻れそうです。

  • LINQ CTP Update はもうすぐ

    Expression Tree について書くと決めてから既に2週間が過ぎてしまいました。 楽しみにしていらっしゃった方、大変申し訳ありません。

    実は、この2週間、次の LINQ Project CTP に追われ、サンプルを書き、バグを直し、そして最終の msi をインストール、アンインストールと毎日、走り回っていました。 その CTP Update もあと残すところあと少し、もうしばらくお待ちください。

    ブログの更新が遅れてしまうかもしれませんが、CTP の作業が終わり次第、定期更新に戻る予定です。

  • DLINQ Is Magic

    昨日と全く反対のタイトルですみません。 なぜか? 昨日書いた事は、今日の Check in で既に過去の物となってしまいました。 言語の視点から見た場合は、ほぼ同じなのですが、DLINQ Engine の視点で見た場合 DLINQ は Magic になってしまいました。 この変更ももちろん LINQ Project Tech Preview を使っていただいている方々からの Feedback によるものですが、アーキテクチャの根幹に関わってくるデザインチェンジです。 次の Tech Preview が出るまでは、詳しく書く事はできませんが、Preview を RTW したあとに詳しく書いてみようと思います。

    DLINQ Magic を書く前に、明日から次の Tech Preview が出るまでの間、変更点または DLINQ そのものを理解するためのキーとなる Expression Tree について書いて見ようと思います。

  • DLINQ は Magic か?

    LINQ Project では In-Memory Query と DLINQ Query に同じ Query Expression が使えます。 コンパイラは Query Expression が In-Memory に対してかそれとも Relational DB なのか分かるのか?と言う質問をよくされます。  コンパイラがすごい事をしていると誤解されているようですので、その説明をちょっとだけ。 

    特に Magic は無く、Trick としては C# 3.0 で新しく追加された
       1. Query Operators はオーバーロード可能
       2.  lambda 式は Expression<Func<...>> にアサインされた場合 Expression Tree を IL の代わりに Emit する

    の二つだけです。例えば、LINQ In-Memory Query の場合
          var q = from x in new int[]{1,2,3,4}
                 where x > 2
                 select x;

                int[] q = (new int[]{1,2,3,4}).Where(x => x > 2);
    に、まず変換されます。ここで使われる Where Operator は
       IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate)
    です。 理由は 普通に Overload  の解決で IEnumerable<T> へ Implicitly Convertable な new int[] が最初の Where Operator の引数だからからです。

    では、DLINQ Query の場合を見てみると、
              var q = from x in db.Customer
                 where x.ContactName == "Hoge"
                 select x;

             q = db.Customer.Where(x => x.ContactName == "Hoge");
    にと書き換えられ、          
             Query<T> Where<T>(this Query<T> source, Expression<Func<T, bool>> predicate)
    の Where Operator が使われます。Trick 1で書いたQuery Operator は Overload 可能がキーポイントです。 最初のdb.Customer プロパティ の戻り値の型は Table<T>。 クラスの関係は
       IEnumerable<T>
          |
       Query
    <T>
          |
       Table
    <T>
    よって、Overload の解決は Table<T> により近い Query<T> へと、つまり、Where<T>(this Query<T>..) の方が Where<T>(this IEnumerable<T> ...) よりも Better となる訳です。 ここで先ほどの Trick の2番目、lambda 式の Expression<Func<..>>への変換が登場します。 Query Expression の中の
          x => x.ContactName == "Hoge"

       Query<T> Where<T>(this Query<T> source, Expression<Func<T, bool>> predicate)
    の Where Operator が使われる事により、2番目の引数、Expression<Func<T, bool>> へとアサインされます。 lambda 式は Expression<Func<...>> にアサインされた事により無事にExpression Tree に書き出される事になります。

    Dlinq Engine は Expression Tree を元に C# から SQL の変換を行い Database へ SQL Query をなげ、結果を得ます。

    このように、LINQ は既存の言語の仕様の上に成り立っていると言うのが分かっていただけたかと思います。

  • 製品を出荷した経験値

    マイクロソフトではいくつの製品の出荷(RTM)に関わったかでいろいろな事が変わってきます。
    例えは、部署を移るときの Requirement の一つ (have shipped more than two products) と書かれている事がよくあります。

    C# のチームを見てみると、やっぱり製品の出荷に最初から最後まで関わったメンバとそうでないメンバとの違いは一目瞭然。 経験のある人は、今の段階、Orcas のプランニングで、どんどんと仕事を見つけ片付け、特に、Whidbey の際、時間がなくて手をつけれなかった仕事に楽しみながら取り組んでいます。

    方や、 Whidbey の途中や最近入った人達は、何処かゆっくり。 この人達は、今しか自由な時間がないことをまったく理解していない、かと言っても、たぶん言って聞かせたところで理解できないのでしょう。 4年前の、自分がそうであったように。

    この違いは開発の後半で大きく響いてきます。 部下を持つ立場として、自分のチーム (DLINQ) には常に、今この時、今が重要だと言い聞かせ、どんどんと仕事を進めさせていますが、ほんとにそれが正しいかどうかは自信がありません。 と言うのも、経験から学ばせた方がいいと思うのですが、後で苦労するのを考えるとついつい。 

    製品を出荷することは、その他いろいろなところに響いてきますが、仕事への取り組み方、どの段階で何をしなければ成らないかを理解する事だけを見ても、なぜ Requirement の一つなのかも納得できると思います。

More Posts Next page »

© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker