Hatena::ブログ(Diary)

猫とC#について書くmatarilloの雑記 Twitter

2014年07月27日

猫と洗濯物

| 猫と洗濯物を含むブックマーク 猫と洗濯物のブックマークコメント

枕にするなよ。

2014-07-27 09.42.13

トラックバック - http://d.hatena.ne.jp/matarillo/20140727

2014年07月09日

ASP.NET MVC 5.2のメモ(Linux)

| ASP.NET MVC 5.2のメモ(Linux)を含むブックマーク ASP.NET MVC 5.2のメモ(Linux)のブックマークコメント

MonoDevelopは4.0Monoは3.2.8をインストール。

デフォルトではMVC 3のプロジェクトテンプレートが入っているから、まずはそれを選んでプロジェクトを作る。

f:id:matarillo:20140709233247p:image

ところがプロジェクトを作るときになぜかエラーが。

System.IO.FileNotFoundException: Could not find file "/usr/lib/monodevelop/AddIns/MonoDevelop.AspNet.Mvc/Templates/Common/Index.cshtml".

同じ現象が起きてる人を見つけた。回答には「MonoDevelopをソースからビルドしろ」とあったが、面倒だったのでGitHubの当該ブランチから足りてなさげなテンプレートファイルを取ってきた。そしたらプロジェクトの作成時にはエラーが出なくなった。

しかし問題はまだあり、ビルドすると警告が出るし、実行するとFileNotFoundExceptionになる。

f:id:matarillo:20140709233249p:image

プロジェクトをよく見たら、参照アセンブリが見つかっていない。

f:id:matarillo:20140709233248p:image

こちらも同じ現象が起きてる人を見つけた。こっちの回答も自分でビルドしろとか言ってる。えー。

そこで慌てず騒がずNuGet Addinをインストールする

そしてもういっそのことASP.NET MVC 5.2を入れることにする。

f:id:matarillo:20140709233251p:image

そしたらアセンブリ参照の警告はなくなったが、実行するとまだエラーになる。今度はInvalidOperationExceptionだ。

f:id:matarillo:20140709233252p:image

Web.configを見ると、Web Pagesのバージョンが1.0になっていたので、3.0に手で直す。

  <appSettings>
    <!-- add key="webpages:Version" value="1.0.0.0" / -->
    <add key="webpages:Version" value="3.0.0.0" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  </appSettings>

これでもまだInvalidOperationExceptionが出る。ただしエラーメッセージはさっきとは違う。

f:id:matarillo:20140709233253p:image

Views/Web.configを見ると、MVC 3の指定が残っていたので、5.2に変える。

	<system.web.webPages.razor>
		<!-- host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc,
                          Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" / -->
		<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc,
                          Version=5.2.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
		<pages pageBaseType="System.Web.Mvc.WebViewPage">
			<namespaces>
				<add namespace="System.Web.Mvc" />
				<add namespace="System.Web.Mvc.Ajax" />
				<add namespace="System.Web.Mvc.Html" />
				<add namespace="System.Web.Routing" />
			</namespaces>
		</pages>
	</system.web.webPages.razor>

これでやっとASP.NET MVCが動いた。

f:id:matarillo:20140709233254p:image

トラックバック - http://d.hatena.ne.jp/matarillo/20140709

2014年07月07日

Entity Framework 6とMySQLのメモ(Windows)

| Entity Framework 6とMySQLのメモ(Windows)を含むブックマーク Entity Framework 6とMySQLのメモ(Windows)のブックマークコメント

nugetで「MySQL.ConnectorNET.Entity」をインストール。他のは無視。

f:id:matarillo:20140707154804p:image

f:id:matarillo:20140707154801p:image

うまくいけば、アセンブリの参照はこんな感じになる。

f:id:matarillo:20140707154803p:image

App.configはこう。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework"
             type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
    <providers>
      <provider invariantName="System.Data.SqlClient"
                type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
      <provider invariantName="MySql.Data.MySqlClient"
                type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6, Version=6.8.3.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"></provider>
    </providers>
  </entityFramework>
  <system.data>
    <DbProviderFactories>
      <remove name="MySQL Data Provider"
              invariant="MySql.Data.MySqlClient" />
      <add name="MySQL Data Provider"
           invariant="MySql.Data.MySqlClient"
           description=".Net Framework Data Provider for MySQL"
           type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.8.3.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
    </DbProviderFactories>
  </system.data>
</configuration>

そこで、EF6 Code Firstのコードを書く。

using System;
using System.Data.Entity;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<BlogContext>());

            using (var db = new BlogContext())
            {
                db.Blogs.Add(new Blog { Name = "aaa" });
                db.SaveChanges();

                foreach (var blog in db.Blogs)
                {
                    Console.WriteLine("BlogId={0},Value={1}", blog.BlogId, blog.Name);
                }
            }
        }
    }

    public class BlogContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }
    }

    public class Blog
    {
        public int BlogId { get; set; }
        public string Name { get; set; }
    }
}

App.configには接続文字列を足す。

  <connectionStrings>
    <add name="BlogContext"
         providerName="MySql.Data.MySqlClient"
         connectionString="Server=localhost;Uid=root;Pwd=XXXX;Database=testdb;"/>
  </connectionStrings>

これで実行しても例外(ConfigurationErrorsException)が発生する。

f:id:matarillo:20140707154802p:image

答えはMySQL Connector/Net Developer Guideに書いてあった。

MySQL用の新しいDbConfigurationクラスを設定しましょう。このステップは省略することもできますが、省略せず設定することを強く推奨します。なぜなら、MySQLのすべての依存関係解決モジュール(dependency resolvers)が追加されるからです。以下の3つの方法があります。

  • コンテキストクラスに DbConfigurationTypeAttribute カスタム属性を付ける。
    [DbConfigurationType(typeof(MySqlEFConfiguration))]
  • アプリケーションのスタートアップコードで DbConfiguration.SetConfiguration(new MySqlEFConfiguration()) を呼び出す。
  • 構成ファイルDbConfiguration 型を設定する。
    <entityFramework codeConfigurationType="MySql.Data.Entity.MySqlEFConfiguration, MySql.Data.Entity.EF6">

カスタムのDbConfigurationクラスを作れば、依存関係解決モジュールを必要なものだけ追加することもできます。

ためしに構成ファイルでやってみた。

  <entityFramework codeConfigurationType="MySql.Data.Entity.MySqlEFConfiguration, MySql.Data.Entity.EF6">
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
    <providers>
      <provider invariantName="System.Data.SqlClient"
                type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
      <provider invariantName="MySql.Data.MySqlClient"
                type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6, Version=6.8.3.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"></provider>
    </providers>
  </entityFramework>

なるほど動いた。

f:id:matarillo:20140707154800p:image

Entity Framework 6とMySQLのメモ(Linux)

| Entity Framework 6とMySQLのメモ(Linux)を含むブックマーク Entity Framework 6とMySQLのメモ(Linux)のブックマークコメント

UbuntuのMonoDevelopが4.0.12で、NuGetアドインを自分で追加しないといけないけど、後の手順は同じでよかった。

(土日に苦労したのは何だったんや……)

f:id:matarillo:20140707191613p:image

トラックバック - http://d.hatena.ne.jp/matarillo/20140707

2014年07月03日

トラックバック - http://d.hatena.ne.jp/matarillo/20140703

2014年06月03日

C#から見たApple Swift

| C#から見たApple Swiftを含むブックマーク C#から見たApple Swiftのブックマークコメント

The Swift Programming Language

C#erによる濁った眼で見たSwiftです。間違いや不足などあればつど修正予定。

C#にもSwiftにもある
C#にもSwiftにもあるがSwiftのほうが強力
SwiftにはあるがC#にはない
  • パターンマッチ
  • タプル(C#のタプルは言語の機能ではない)
  • 代数的データ型(enumが該当)
  • ARC(言語の機能ではないけど)
  • デイニシャライザー(これってC++のデストラクタ―かな)
  • 委譲(Obj-Cのデリゲートと同じもので、C#のデリゲートとは違う)
  • 範囲演算子
  • エイリアス
  • immutableサポート
  • ユーザー定義演算子
C#にはあるがSwiftにはなさそう
  • 名前空間
  • 構造化例外
  • デリゲート(C#のデリゲート。もうあまり使わない機能だしどうでもいいが……)
  • イベント(Swiftでは、クロージャを渡してコールバックしてもらうとか、PropertyChangedイベントについてはプロパティオブザーバー対応するとか、そんな感じ)
  • ジェネレータ(yield return)
  • 非同期サポート(Obj-CやSwiftではGCDを使うようだ)
  • 変性
  • リフレクション(ランタイムの性質上しょうがない)
  • GC(言語の機能ではないけど)
C#にもSwiftにもなさそう
トラックバック - http://d.hatena.ne.jp/matarillo/20140603

2014年05月26日

ネネの反復運動

| ネネの反復運動を含むブックマーク ネネの反復運動のブックマークコメント

腹を見せるだけじゃ飽き足らず、左右に向きを変えてくるのは何なんだ。

D

トラックバック - http://d.hatena.ne.jp/matarillo/20140526

2014年05月17日

続・C#のジェネリクスで型クラスを真似る

| 続・C#のジェネリクスで型クラスを真似るを含むブックマーク 続・C#のジェネリクスで型クラスを真似るのブックマークコメント

前回のエントリ

前回のコード(GitHub Gist)は、値を入れるValue<TImpl, T>クラスが単なるDictionary<string, object>のラッパーでしかなく、汚れ仕事押し付けた形となっていた。

https://cacoo.com/diagrams/pVKta8cnZB9JPLye

そこを何とかしようと思うと、今回のコード(GitHub Gist)みたいになる。

https://cacoo.com/diagrams/RL7zrWc6yyc46wa9

とはいえ、型クラスもどきの方は型引数TImplに実装クラスMaybeを入れられるが、値クラスの方は型引数を使ったとしても実装クラスMaybe<T>ジェネリックのため指定できない。(型引数を取る型引数が不可能、というのにやられているわけだ。)

なのでMaybe<T>を引き回すことができない。型クラスもどきのメソッドを呼び出すたびにMonad<Maybe, T>Functor<Maybe, T>にアップキャストされてしまうのだ。そこで仕方なく、明示的なダウンキャストでMaybe<T>に戻さないといけなくなる。

トラックバック - http://d.hatena.ne.jp/matarillo/20140517

2014年05月07日

MonoDevelopとXamarin Studio

| MonoDevelopとXamarin Studioを含むブックマーク MonoDevelopとXamarin Studioのブックマークコメント

http://monodevelop.com/

Xamarinの中の人から教えてもらった上で私が理解したこと:

というわけで改名したというのはまちがいだが、MonoDevelopの公式サイトをXamarin社が管理している限りは、バイナリパッケージはXamarin Studioの名で配布されるのではないだろうか。

トラックバック - http://d.hatena.ne.jp/matarillo/20140507

2014年04月29日

C#のジェネリクスで型クラスを真似る

| C#のジェネリクスで型クラスを真似るを含むブックマーク C#のジェネリクスで型クラスを真似るのブックマークコメント

id:Nagise さんのJavaジェネリクス記事を読みながら、C#ではどうかな、とあれこれ考えているわけです。

そんな時に、 ジェネリクスのカリー化 - プログラマーの脳みその話を振られて。

真の高階型引数、つまり、型パラメータを取る型パラメータは実現できないです。が、型クラス的なものであればエミュレートできるらしい。

もちろんCLRにもILにも型クラス的なものなんかないわけで、オダスキー教授が言うところの「貧者の型クラス(pdf)」を使う、つまり型に適合するメソッド群をインスタンスとして渡してやるしか方法はないわけですが(ちなみにScalaでは、そのインスタンスを暗黙的に生成したり渡したりできる仕掛けがある)。

というわけで、最初に書いたのがこっちなんだけど…

https://gist.github.com/matarillo/11392331

(追記)ん?型クラス(もどきインスタンス)、new()制約をつけられるんじゃないの?

ということは?

public static class MonadEx
{
    public static Value<TMonad, TResult> SelectMany<TMonad, TSource, TCollection, TResult>(
        this Value<TMonad, TSource> source,
        Func<TSource, Value<TMonad, TCollection>> collectionSelector,
        Func<TSource, TCollection, TResult> resultSelector)
        where TMonad : Monad<TMonad>, new()
    {
        var monad = new TMonad();
        return
            monad.Bind(source, x=>
                monad.Bind(collectionSelector(x), y=>
                    monad.Unit(resultSelector(x,y))));
    }
}

まさか?

internal class Program
{
    private static void Main(string[] args)
    {
        var m =
            from x in Maybe.Instance.Unit(12)
            from y in Maybe.Instance.Unit(34)
            select x + y;
        var message =
            m.HasValue()
                ? m.Value().ToString()
                : "Nothing";
        Console.WriteLine(message);
    }
}

いけるじゃないか!!


(追記)new制約つけてnewしましたが、よーく考えると、Valueクラスの中に型クラスもどきインスタンスを持つようにするとか、あるいはタプルで型クラスインスタンスとValueクラスのインスタンスをまとめて扱うようにする方法もありますね。そしたら型クラスもどきインスタンスを使いたい側でnewしなくても、Valueと一緒に受け取れるはず。


https://gist.github.com/matarillo/11393891

using System;
using System.Collections.Generic;

internal class Program
{
    private static void Main(string[] args)
    {
        var m =
            from x in Maybe.Instance.Unit(12)
            from y in Maybe.Instance.Unit(34)
            select x + y;
        var message =
            m.HasValue()
                ? m.Value().ToString()
                : "Nothing";
        Console.WriteLine(message);
    }
}

public abstract class TypeClass<TImpl>
{
}

public abstract class Functor<TImpl> : TypeClass<TImpl>
{
    public abstract Value<TImpl, TResult> Map<T, TResult>(
        Value<TImpl, T> m,
        Func<T, TResult> f);
}

public abstract class Applicative<TImpl> : Functor<TImpl>
{
    public abstract Value<TImpl, T> Pure<T>(T value);

    public abstract Value<TImpl, TResult> Ap<T, TResult>(
        Value<TImpl, T> m,
        Value<TImpl, Func<T, TResult>> mf);

    public override Value<TImpl, TResult> Map<T, TResult>(
        Value<TImpl, T> m,
        Func<T, TResult> f)
    {
        return Ap(m, Pure(f));
    }
}

public abstract class Monad<TImpl> : Applicative<TImpl>
{
    public abstract Value<TImpl, T> Unit<T>(T value);

    public abstract Value<TImpl, TResult> Bind<T, TResult>(
        Value<TImpl, T> m,
        Func<T, Value<TImpl, TResult>> f);

    public override Value<TImpl, T> Pure<T>(T value)
    {
        return Unit(value);
    }

    public override Value<TImpl, TResult> Ap<T, TResult>(
        Value<TImpl, T> m,
        Value<TImpl, Func<T, TResult>> mf)
    {
        return Bind(m, x => Bind(mf, f => Unit(f(x))));
    }
}

public class Maybe : Monad<Maybe>
{
    public static readonly Maybe Instance = new Maybe();

    public static Value<Maybe, T> Nothing<T>()
    {
        return new Value<Maybe, T>();
    }

    public override Value<Maybe, T> Unit<T>(T value)
    {
        return new Value<Maybe, T>().SetValue(value);
    }

    public override Value<Maybe, TResult> Bind<T, TResult>(
        Value<Maybe, T> m,
        Func<T, Value<Maybe, TResult>> f)
    {
        return (m.HasValue()) ? f(m.Value()) : Nothing<TResult>();
    }
}


public class Value<TImpl, T>
{
    private readonly Dictionary<string, object> _fields
        = new Dictionary<string, object>();

    public void Set(string name, object value)
    {
        _fields[name] = value;
    }

    public TField Get<TField>(string name)
    {
        object o;
        if (_fields.TryGetValue(name, out o))
        {
            return (TField)o;
        }
        return default(TField);
    }
}

public static class MonadEx
{
    public static Value<TMonad, TResult> SelectMany<TMonad, TSource, TCollection, TResult>(
        this Value<TMonad, TSource> source,
        Func<TSource, Value<TMonad, TCollection>> collectionSelector,
        Func<TSource, TCollection, TResult> resultSelector)
        where TMonad : Monad<TMonad>, new()
    {
        var monad = new TMonad();
        return
            monad.Bind(source, x=>
                monad.Bind(collectionSelector(x), y=>
                    monad.Unit(resultSelector(x,y))));
    }
}

public static class MaybeEx
{
    public static Value<Maybe, T> SetValue<T>(this Value<Maybe, T> m, T value)
    {
        m.Set("HasValue", true);
        m.Set("Value", value);
        return m;
    }

    public static bool HasValue<T>(this Value<Maybe, T> m)
    {
        return m.Get<bool>("HasValue");
    }

    public static T Value<T>(this Value<Maybe, T> m)
    {
        if (m.HasValue())
        {
            return m.Get<T>("Value");
        }
        throw new InvalidOperationException();
    }
}

xuweiさんにもコメントもらいたいなあ。

2014年04月22日

YコンビネータっていうかZコンビネータでラムダ式が再帰関数に変わるからフィボナッチ数も計算できる、Java8版

| YコンビネータっていうかZコンビネータでラムダ式が再帰関数に変わるからフィボナッチ数も計算できる、Java8版を含むブックマーク YコンビネータっていうかZコンビネータでラムダ式が再帰関数に変わるからフィボナッチ数も計算できる、Java8版のブックマークコメント

Java8も出たことだし、ラムダ式で頑張ってみました。

たぶんこういうことだと思いますが、詳しくはきしださんに聞いた方がいいのでしょう。

おとうさん、ぼくにもYコンビネータがわかりましたよ! - きしだのはてな

下のコードQiitaにも置きました

(追記)rec.applyRec(rec)自分自身に名前を付けて呼び出してるからレギュレーション違反、と言われそうな気がしたので、ちょっとだけ修正変数で受けてるのは、キャストするのがアレだな、1行が長くなるのが嫌だな、と思っただけのこと。変数で受けずに1行で書くことは可能です。

package example;

import java.util.function.*;

public class Program {
  public static void main(String[] args) {
    Function<Integer, Integer> fib
      = Y(f -> n -> n > 1 ? f.apply(n - 1) + f.apply(n - 2) : n);
    System.out.println(fib.apply(8));
  }

  static <A, R> Function<A, R> Y(Function<Function<A, R>, Function<A, R>> f) {
    Recursive<A, R> rec1 = r -> a -> f.apply(r.applyRec(r)).apply(a);
    Recursive<A, R> rec2 = r -> a -> f.apply(r.applyRec(r)).apply(a);
    return rec1.applyRec(rec2);
  }
}

@FunctionalInterface
interface Recursive<A, R> {
  public Function<A, R> applyRec(Recursive<A, R> f);
}
トラックバック - http://d.hatena.ne.jp/matarillo/20140422

2014年04月18日

オープンソースは報われない仕事。でもやるんだよ。

| オープンソースは報われない仕事。でもやるんだよ。を含むブックマーク オープンソースは報われない仕事。でもやるんだよ。のブックマークコメント

Microsoftの中の人で、OSSとWeb技術を推進するScott Hanselmanが書いたブログ記事 "Open Source is a thankless job. We do it anyway." を勝手翻訳

オープンソースは報われない仕事。でもやるんだよ。

オープンソースは難しい。

セキュリティは難しい

OpenSSLの最近の "Heartbleed" バグに関する記事がたくさん出回っている。技術的な分析をすべて読んだら丸一日つぶれてしまうだろうが、 その中にこれはと思う見出しがあった。『OpenSSLはオープンソースの大きな問題を示している。資金不足、人員不足』だ。インターネットを織りなす基本の部分は、ほとんどの場合、たった一人と多くのボランティアによるものだ。

猝ハ播で気が遠くなるような事実とは、ネットワークインフラストラクチャにはこのように重大な部品存在していて、インターネットの大部分で実際に動いているのだけれど、基本的にはフルタイムで作業しているのはたった一人しかいないということだ。

さらに、あるソフトウェアが動作している間は、私たちは貢献者たちの努力成功を褒め称えたりはしない。その代わり、たった一行(重要な行の一つではあったが)が期待に応えなくなるのを待っている。このいまいましい無料の、おおむね動作する、世界規模で接続されたネットワークを動かしているソフトウェアめ。使えねーな。

オープンソースとは、おおむね報われない仕事だ。Microsoft .NETコミュニティの場合、時々むなしくなったりもする。ボランティアが全然見つからないことがあるのだ。多くの人々が、デフォルトのものやVisual Studioに同梱されているものを使う。RailsとかNodeの場合は、企業支援もあるが、プロジェクトはコミュニティが駆動しているという認識がある。現実は中間なのだが、Microsoftのスタック上に構築されたオープンソースプロジェクトでは、ボランティアが「我々は、出荷されたものをただ使うのみだ」なんて言うことがある。

マイクロソフトの過去の行動に対しては「怒り」が存在するけれども、前にも言ったように彼らは「長い」道のりを越えてきた。私はこれからもMicrosoftでオープンソースを推進していく。もう押すのは終わり!これ以上押せない!と思うまでは。内部では地殻変動が進んでいる。ミスはあったが正しい方向に進んでいる。誰もが学びの途中だ。

注目されるのは難しい

Jeremy Millerのチームは”FubuMVC”という.NETのオープンソースフレームワークのアクティブな開発を最近停止した。彼の最終的なブログ記事には、NETオープンソースの存続可能性に関する問題が書かれていた。

犲造リアルな疑問、つまり.NETのOSSとは見込みがある計画なのかという疑問を置いておくとしても(答えはおおむね否だ、いくらScott Hanselmanが声を枯らしてそんなことはないと言おうともね)、FubuMVCは失敗した。なぜなら我々は――多分ほとんどは私のせいなのだ、なぜならこれまでのところ最も目立っていたのは私だからだ――自分自身を売り込み、ブログ記事やドキュメントカンファレンスでの発表を通じてコミュニティを構築する努力が足りなかったからだ。

これはまさに真実をついている。多くのオープンソースプロジェクトにとっては、広い意味での可視性が存続可能性の元となっているのだ。Jeremyのふりかえりは素晴らしいのでぜひ読んでみてほしい。

大規模なフレームワークが既に存在しているところに、代替手段となるような大規模フレームワークのプロジェクトを立ち上げるのは難しいことだと思う。多くの人にとってはデフォルトを使用する方が簡単だからだ。FubuMVC、OpenRasta、ServiceStack、Nancyなどのようなフレームワークはすべて「新たにデフォルトを考え直した」ものだ。それらは(いい意味で)独断を行った大規模フレームワークなのであり、現状に甘んじないものたちだ。しかし、大規模フレームワークが支持者を育てるのは、HumanizerJSON.NET のような小さなライブラリよりもはるかに難しいことだ。

それでも、こういったプロジェクトがなければ我々はみんなデフォルトを使用したままだっただろうし、コミュニティとして新しいアイデアを探求したり限界ギリギリを攻めたりすることはなかっただろう。F#のFAKEビルドシステムや、Chocolateyや、Boxstarterみたいには。

MicrosoftはOSSプロジェクトを今よりよい方法でサポートできる。単にライセンスお金だけではなく、可視性においても。Microsoftの全カンファレンスで、オープンソースにトラック提供するよう提案したい。オープンソースコミュニティのメンバーがしゃべる枠を作るのだ。DotNetConfが手始めだが、拡大していけるはずだ。

組織化は難しい

OWINが良い例だ。小さいけれどとても重要なプロジェクトで、.NET界に影響を与えている。しかし組織化に苦労している。それをうまくやることは将来のために重要になってきている。コミュニティの中に小さいけれども影響力を持っているグループがあり、彼らは妥協点を見つけて技術的な問題にまつわるコンセンサスを構築しようとする努力を数か月間続けてきている。

ASP.NET Web APIとSignalRはどちらもOWIN (Open Web Interface in .NET) というオープンソースプロジェクトの上に構築されている。OWINはサーバ、フレームワーク、およびミドルウェアの密結合を分離することが目的だ。

GitHub上に開かれたままのissueがある。その問題は曖昧だがOWINに関して重要な点をついているように思われる。OWINの仕様にはIAppBuilderというインタフェースは含まれていないが、Microsoftのサンプルコードのほとんどにおいて、IAppBuilderはデフォルトで使用されている。根底を支えるOWINフレームワークは中立を保つことができるのか?このissueは長く、何度か横道に脱線している。複雑な問題であり、完全に理解しているのはおそらく20人ぐらいだろう。

Scott KoonはOWINのガバナンスドキュメントに関して頑張っていたが、建設的な動きを目にすることはなかった。彼は不満をTwitterで漏らした。当然のことではある。よく使われる「怠惰なコンセンサス」の技では、人々が沈黙しているか72時間以内に返信しなかった時は、事実上同意したものと見なし、プロジェクトの方向性を変更することができる。積極的な関与こそが重要なのだ。

オープンソースの華はプルリクエストコーディングだけれども、コードを作る前に合意を形成する必要がある。このプロセスの中で最も論争を生む部分は所有権だ。所有権とはコントロールのことだ。方向をコントロールすること。所有権の問題を通じて落としどころを見つけて作業するための鍵は、全員の異なる目標を徹底的に理解して共通のビジョンを見つけることだ。共通のビジョンによって、コミュニティが結集し前進できる。

このソーセージ製造工程は退屈な汚れ仕事だが、必要なのだ。OSSにおいてはコードが占めるよりも多くの部分をこれらの議論が占めている。押しと引きは同程度が必要だ。

関わることは難しい

私は毎週、何十通もの電子メールを受け取る。それらはすべて「オープンソースに関わるにはどうすればいいのでしょうか?」と尋ねるものだ。どうやら誰もが、私の回答は「コードを書け」とか「プルリクエストを送れ」とか、場合によっては「ドキュメント書きを手伝え」だろうと予想しているようなのだ。

実際には、やれることはそれがすべてではない。みんながやるべきことは、読むこと。吸収すること。理解すること。歓迎し、受け入れ、親切にすること。思慮深い分析を提供し、質問をすること。誇張や炎上を招くような言葉を避けること。issueにコメントする際はコード例を示すこと。人の手助けをすること。

ブログ記事はコミュニティを動かすエンジンなのである。オープンソースのコミットも、ドキュメント書きも、プロモーションも、サンプルも、講演も、コード片も、確かに重要なことだ。しかし、オープンソースに関わるということは、「プロジェクトをフォークして、あなたの世界観を反映する巨大なプルリクエストを送信する」ことを必ずしも意味しない。地味な作業が重要なことも時にはある。ガバナンスドキュメントを書いたり電話会議をまとめたり、GitHubの巨大なissueのスレッドで質問をする前に徹底的に読んだりすることが。

なぜこんなことをするのか?モテるためでも金のためでもない。我々が構築者だからだ。誰でもぜひ参加してほしい。やるべきことはたくさんある。

2014年03月21日

朝飯をねだるウナ

| 朝飯をねだるウナを含むブックマーク 朝飯をねだるウナのブックマークコメント

気づくと枕元にいる。そして噛む。噛むなよ。

photo

2014年01月26日

猫の首輪

| 猫の首輪を含むブックマーク 猫の首輪のブックマークコメント

ちょっとわかりにくいですが、チュッパチャップスの首輪にしました。

鈴は取り外してあります。

http://flic.kr/p/jvJxZ4

トラックバック - http://d.hatena.ne.jp/matarillo/20140126

2013年12月17日

Java8とC#

| Java8とC#を含むブックマーク Java8とC#のブックマークコメント

このエントリーは「C# Advent Calendar 2013」の17日目のエントリーです。

前日は id:ksasao さんの「GDI+ で描画&保存あれこれ - まちみのな@はてな」でした。


Java 8は2014年3月リリースされる予定です。

どういう変更が含まれているのかは、Java 8のすべてにまとめられています。

また、きしださん(id:nowokay)のように、Java8に関する記事をたくさん書いている人もちらほらいます。

この記事では、InfoQの記事(および参照元の英語ブログ)を参考に、Java8の新機能をC#と比べてみたいと思います。

インターフェースの改善

インターフェースでstaticメソッド定義できるようになった

もともと、JavaのインターフェースはC#のインターフェースと違って、static finalなフィールドを持つことができました。

static finalなフィールドというのは、C#で言うと、constで修飾された定数と、static readonlyで修飾された読み取り専用フィールドの両方に対応します。

Java 8では、static finalなフィールドに加えて、staticなメソッドの実装も含むことができるようになっています。

C#のインターフェースは、メソッド、プロパティ、イベント、インデクサの宣言しかできません。フィールドとかメソッド実装とかは、インターフェースとは別のクラス(たとえばstaticクラス)に定義するしか方法がありません。まあ、それでも用は足りるでしょうが、別のクラスを定義するのが面倒な人もいるでしょうね。

デフォルトメソッドの定義が可能になった

こっちは、staticなメソッドではなく、インスタンスメソッドです。宣言だけではなくてデフォルト実装を定義できるようになります。デフォルト実装があるメソッドは、実装クラス(implementsするクラス)に実装を定義しなくても、そのメソッドがインスタンスメンバーとして定義されているかのように動きます。

なぜデフォルトメソッドか?というと、interfaceに新しいメソッドを追加したいんだけれども、ただ追加すると既存の実装クラスが全部コンパイルできなくなってしまうからできない、そこでメソッドのデフォルト実装が提供できれば、既存の実装クラスに影響を与えずに新しいメソッドを追加できる、と、こういう理屈です。

C#の場合は、後からメソッドを追加したいという要求には、拡張メソッドという解決法が提供されています。LINQの標準クエリ演算子がその代表例ですね。拡張メソッドの場合は、「元の型の実装を全く変えずに、第3者が拡張メソッドを提供できる」という特徴があります。Java 8ではそのようなことはできません(デフォルトメソッドを定義できるのはインターフェース提供者のみ)が、そのかわり、「メソッド実装の多重継承ができる」「デフォルト実装をオーバーライドすることで、より適した実装に差し替えることができる」という特徴があります。

public interface Foo {
    // 定数
    public const int INT_CONST = 10;
    // 読み取り専用静的フィールド
    public static List<String> LIST_FIELD = new ArrayList<String>();  
    // 【Java8】staticメソッドの実装
    public static int getSize() {
        return LIST_FIELD.size();
    }
    // 抽象メソッド
    public String bar();
    // 【Java8】メソッドのデフォルト実装
    public default int baz() {
        return 42;
    }
}

C#だとこんな感じですが、定数、静的フィールド、staticメソッドがIFooと無関係になってしまいますね。

public interface IFoo
{
    string Bar();
}

public static class Foo
{
    // 定数
    public const int IntConst = 10;
    // 読み取り専用静的フィールド
    public static readonly List<string> ListField = new List<string>();  
    // staticメソッドの実装
    public static int GetSize()
    {
        return ListField.Count;
    }
    // 拡張メソッド
    public static int Baz(this IFoo @this)
    {
        return 42;
    }
}

関数型インターフェース

C# で言うところのデリゲート(delegate)に相当する型は、Java 8では「関数型インターフェース」という名前のインターフェースです。

関数型インターフェースは、toString()以外の抽象メソッドを1つだけ持つインターフェースのことです。

@FunctionalInterfaceというアノテーションをインターフェースにつけておくと、そのインターフェースが関数型インターフェースでないとコンパイルエラーになります。

ただし、@FunctionalInterfaceがなくてもコンパイルは通りますし、後述するラムダ式やメソッド参照も使うことができます。まあなんというか、設計意図コードに埋め込むためだけのものですね。

C# で言うところのデリゲート相当とは言いましたが、C#みたいに+演算子や-演算子を適用して結合したり削除したりすることはできませんし、BeginInvokeEndInvokeによる別スレッド呼び出しなんかもできません。まあC#でもこのあたりの機能は黒歴史というか、なくてもいいので……

@FunctionalInterface
public interface Foo {
    // さっきのFooインターフェースと同じように、
    // 定数やフィールドや静的メソッドやデフォルトメソッドを
    // 定義していたとしても、
    // 抽象メソッドが1つだけであればOK
    public String bar();
}
public delegate string Foo();

ラムダ

C# のラムダによく似た記法のラムダ式が入りました。

goes toの記号が違うだけで、後はほぼ同じです。

Javaとしては、ラムダがなくても匿名内部クラスがあればほぼ同等のことは実現できるのですが、やはり記述が面倒くさいということで、より簡潔に書ける記法としてラムダが導入されています。

ただし、ラムダで書いたときと匿名内部クラスで書いたときは、コンパイル結果が異なります(ただのシンタクティックシュガーではないです)。ここも掘ると面白いのですが、C#とは関係ない世界なのでやめておきましょうか。

(int x, int y) -> { return x + y; }
(x, y) -> x + y
x -> x * x
() -> x
x -> { System.out.println(x); }

C#の場合はdelegateキーワードを使った匿名メソッドによる記法も有効です。でもまあラムダでいいでしょう。

(int x, int y) => { return x + y; }
(x, y) => x + y
x => x * x
() => x
x => { Console.WriteLine(x); }

// 匿名メソッド
delegate(int x, int y) { return x + y; }
// 引数を使わない場合は省略できる謎仕様
Func<int, bool> pred = delegate { return true; };

メソッド参照

C#のデリゲートが名前付きメソッドに関連付けることができるのとほぼ同じです。

String::valueOf  // x -> String.valueOf(x)
Object::toString // x -> x.toString()
x::toString      // () -> x.toString()
ArrayList::new   // () -> new ArrayList<>()

C#の場合は::じゃなくて.ですね。

ただし、C#の場合はコンストラクタをデリゲートに入れる方法がありません。

Convert.ToString // x -> Convert.ToString(x)
x.ToString       // () -> x.ToString()

ラムダとキャプチャ

Javaの場合は、匿名内部クラスと同じように、finalまたは実質的finalである変数しかキャプチャできません。

つまり、読み取り専用変数を読み取ることしかできないということなので、いわゆるクロージャとは若干異なります。

C#ではそういう制限はありません。メンバー変数やローカル変数を書き換えることが可能です。

java.util.function

Java 8には、Function<T, R>Predicate<T>Consumer<T>Supplier<T>BinaryOperator<T>といった関数型インターフェースが標準ライブラリに入りました。

C#のデリゲートとの対応を書いてみましょうか。

Java 8 関数型インターフェースC# デリゲート
Function<T, R>Func<T, TResult>
Predicate<T>Func<T, bool>またはPredicate<T>
Consumer<T>Action<T>
Supplier<T>Func<T>
BinaryOperator<T>Func<T, T, T>

C#のLINQの場合は、Func<T>およびAction<T>の汎用デリゲートに寄せていますが、Java 8では使われ方を表すインターフェースが用意されているようです。

個人的には、C#の汎用デリゲートは「静的型付け言語では型がドキュメントになる」とは言えないので、そんなに好きじゃないです。

java.util.stream

要素のシーケンスで、その要素は必要になって初めて取り出されます。C# で言うところのIEnumerable<T>と、それに対する拡張メソッド群、すなわちLINQに相当します。

APIドキュメントの非公式翻訳java.util.stream (java.util.stream API仕様 b128 非公式翻訳)にあります。

この、ネームスペース解説文が網羅的で良いと思います。

高階関数処理と列挙

C# では、IEnumerable<T>に対して列挙もできるし、LINQ、つまり高階関数による処理もできるのですが、Javaの場合は、列挙用のインターフェース Iterable<T> と 高階関数処理用のインターフェース Stream<T> が分かれています。

これはどうしてでしょうか?

理由のひとつは、ジェネリクスの実装方式が違うためです。

C#では、すべてのジェネリックコレクションと配列がIEnumerable<T>を実装しますが、Javaの場合は、配列はIterable<T>インターフェースを実装しません*1。なので、もしIterable<T>を高階関数処理の対象とすると、配列をIterable<T>に変換する必要が出てきます。

ところがところが、Javaのジェネリクスはプリミティブ型(値型)に対応していないという制約があります。なので、たとえばint[]を変換するとしたら、intのラッパークラスであるIntegerを列挙するIterable<Integer>に変換することはできるかもしれませんが、そうするとボックス化/ボックス化解除が発生するのでパフォーマンスは落ちます。

ボックス化/ボックス化解除を無くしたい場合は、Iterable<T>とは別の型、たとえばIntIterableみたいなプリミティブ型に特化した型*2を新たに作って、そこに変換するしかありません。でもこの型、列挙のためではなくって、高階関数処理のために作ったんだよね……

というわけで、どうせプリミティブ型向けの高階関数処理インターフェースは新たに作らなければならないのだから、いっそのこと全部新しいインターフェースでいいじゃないか、というわけで、オブジェクト用にはStream<T>を、プリミティブ型にはIntStreamLongStreamDoubleStreamを用意したというわけです。

理由のもう一つは、こちらの方が重要なのですが、要素へのアクセス方法と高階関数処理を明確に分離することで、データ構造に適した形で高階関数処理の実装を提供するためです。

C#では、たとえ元のコレクションが木構造だったとしても、Select()などのLINQを適用するとIEnumerable<T>を経由することになってしまい、構造が壊れます。

Java 8では、高階関数処理メソッドは抽象メソッドで、デフォルト実装もありません。木構造用のStream<T>実装を用意すれば、構造を壊さずにmap()などのメソッドを呼び出すことができるでしょう。

LINQの標準クエリ演算子との対応

進捗ダメです。後で書きます。

reduceとcollect

進捗ダメです。後で書きます。

ジェネリック型インターフェースの改善

InfoQの記事によれば、推論が賢くなったみたいです。

C#はまだ貧弱ですね。

class Program
{
    static void Main(string[] args)
    {
        // Java 8みたいに Foo(Utility.Bar()); とは書けない
        Foo(Utility.Bar<FooBar>());

        // Java 8みたいに Utility.Foo().Bar(); とは書けない
        Utility.Foo<FooBar>().Bar();
    }

    static void Foo(FooBar fb)
    {
        Console.WriteLine(fb.Baz);
    }
}

class FooBar
{
    public string Baz = "Baz";

    public void Bar()
    {
        Console.WriteLine("Bar");
    }
}

static class Utility
{
    public static T Foo<T>() where T : class, new()
    {
        return new T();
    }

    public static T Bar<T>() where T : class, new()
    {
        return new T();
    }
}

java.time

きしださんによれば、「めんどくささが増しつつ非常に高機能になりました。」とのことです

C#だと、ローカル時間UTC区別だけできるDateTime構造体、時差を含められるDateTimeOffset構造体、時刻または時間範囲を表すTimeSpan構造体、

タイムゾーンを表現するTimeZoneクラスとTimeZoneInfoクラス、夏時間の期間を表現するDaylightTimeクラス、1つ以上の時代(年号)をもつ暦を表現するCalendarとその派生クラスで和暦を表現するJapaneseCalendar、とこんなところですかね。

C#でもJavaでも、このあたりは非常にややこしいです。C#の場合はDateTime構造体からDateTimeOffset構造体へは暗黙の型変換がありますが、TimeZoneクラスとTimeZoneInfoクラスには互換性はないですね。

Collections APIの拡張

IterableCollectionListMapといったコレクションインターフェースにいくつかデフォルトメソッドが追加されました。重要なのはストリームに変換するstream()メソッドや並列ストリームに変換するparallelStream()メソッドですが、他にも関数型インターフェースを引数にとるforEach()なんかも追加されています。

C#の場合は、すべてのジェネリックコレクションと配列はIEnumerable<T>を実装しているので、「ストリームに変換」する必要はありません。ただし、PLINQで並列処理したい場合は、ParallelEnumerable静的クラスに定義されたAsParallel()拡張メソッドを呼び出す必要があります。

それと、IEnumerable<T>にはForEach()拡張メソッドは用意されていません(LINQに副作用を持ち込みたくないということらしいです)。ForEach()したいときはList<T>クラスを使うか、自分で拡張メソッドを書くか、どちらかですね。

Concurrency APIの拡張

並行プログラミングAPIが拡充されてます。上で書いた並列ストリームに関係する機能もいくつか入っているようです。

C# (というか .NET Framework) の場合はおおむねTPLに対応するという認識です。

Concurrent=並行 と Parallel=並列 の意味の違いは……やめましょうこの話は。

リフレクションとアノテーションの変更

アノテーションというのはC#で言うところのカスタム属性に相当します。

Java8では、型アノテーションと言って、型を利用するところにはどこでもアノテーションをつけられるそうです。

new @Interneed MyObject();
new @NonEmpty @ReadOnly List<String>(myNonEmptyStringSet);
class UnmodifiableList<T> implements @Readonly List<@Readonly T> { ... }
void monitorTemperature() throws @Critical TemperatureException { ... }
myString = (@NonNull String) myObject;
boolean isNonNull = myString instanceof @NonNull String;
class Folder<F extends @Existing File>{ ... }
Doc @Readonly [][] d2 = new Doc @Readonly [2][12]; // Doc の配列の "read-only な配列"

(http://www.slideshare.net/kimuchi583/r5-3-type-annotationより)

C#では今のところできませんが、Java 8でも「こう言うコードが書ける」だけらしいので、まああまり気にしなくてもいいかも。

IO/NIO APIの拡張

Nashorn JavaScript エンジン

java.lang, java.uti, その他の拡張

このあたりは、C#と比べて語るようなことは特にないので省略します。

*1:じゃあ配列を拡張for文で列挙したいときはどうするの?というと、コンパイラが特別扱いします

*2:apache.commonsライブラリにはこういうインターフェースがあります

2013年12月12日

ハイパフォーマンスASP.NETの夢

| ハイパフォーマンスASP.NETの夢を含むブックマーク ハイパフォーマンスASP.NETの夢のブックマークコメント

One ASP.NET Advent Calendarに乗っけるようなネタにはなってないので、とりあえずこっそり書き散らす。

いろんな実行環境、いろんなWebフレームワークマイクロベンチマークをとってる「TechEmpower Framework Benchmarks」というのがあって、しばらく前からちょっと話題になってたみたいです。

測定用アプリはGitHubで公開してて、プルリクエストも受け付けてます。だもんで、「XXフレームワークがないぞ」とか「YYフレームワークの実力はこんなもんじゃねえ」とかいった人たちがどんどんコードを投げ込んでて、TechEmpowerの方でもときどきベンチマークを再測定しているのです。現在の最新は2013/10/31に測定された、Round 7です。

で、ASP.NET。まあ健闘してはいます。全体的に見ればそんなに悪くない。ただ、「シンプルなオブジェクトをJSONにシリアライズして返す」というベンチの結果を見ると、Javaのサーブレットが圧倒的。Responses/Secondのピーク値が、「aspnet」(これ、ASP.NET MVCをIIS上で動かしてるやつです)のざっと7.6倍。で、もっと軽く速くしようっていうので、各種HTTPモジュールを外して、シンプルなHTTPハンドラ(ashxですらない、つまり、SimpleHandlerFactoryも通さない)で実装したのが「aspnet-stripped」。こうすることで「aspnet」の2.1倍にはなったものの、まだまだ*1

http://www.techempower.com/benchmarks/#section=data-r7&hw=i7&test=json&f=1kw-13ydj4-q2w

Javaのサーブレットはなんでそんなに高性能なんだろうと思ったんですが、最近のJavaアプリケーションサーバーのWebサーバー部分は高性能なんですね。GlassFishのコアであるGrizzlyや、もとJBoss AS、現WildFlyのコアであるUndertowは、非同期I/Oを使って実装されてるようです。どうも、そのあたりがJSONベンチにはうまくハマってて、すごい性能をたたき出しているみたいです。

で、ぼくらの(?) ASP.NET はどうすべえという話です(別に何も気にしなくていい、という意見もあろうかと思いますが、こんなに差がついてたら悔しいじゃん?)

試したいのは、非同期I/Oによるサーバでしょうかね。.NETにはFireflyというサーバ実装があります。KayakやManosはもうメンテされていないっぽいので、こっちのほうがいいのかなと思ったけど、こっちも最新コミットは9か月前ですね……

うーむ。これでがんばるのはしんどいのかな?

しばやんも記事を書いていましたが、Heliosを使って旧来のASP.NETスタックを使わなかったら、ちょう速かったよ、ただしセルフホスト、テメーはダメだなんてなベンチも出てることですし、IISを凌ぐ非同期I/OなWebサーバは難しいのかな?Edge.jsのほうがよかったりする?

……と、そこまで書いておきながら、まだ試してないんです。すみませんすみません。

(追記)

あ、ほんとだ……

http://www.techempower.com/benchmarks/#section=data-r7&hw=i7&test=json&f=1kw-13ydj4-ux4

http-listener」(HTTP.sysのラッパーであるHttpListsnerクラスをシンプルに使うやつ、OWINですらない)がさすがに速いですね。でもこれもJSONシリアライザを変えたらもちょっと速くなりそうな気もする。

*1:JSONシリアライザをJSON.NETに変えることでも速くなると思います

トラックバック - http://d.hatena.ne.jp/matarillo/20131212