...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

std.traits.isCovariantWith

import std.traits;

interface I { I clone(); }
class C : I
{
    override C clone()   // I.clone() の共変オーバーライド
    {
        return new C;
    }
}

void main()
{
	{
		static assert(isCovariantWith!(typeof(C.clone), typeof(I.clone)));
	}{
		C function() derived;
		I function() base;
//		static assert(is(typeof(derived) == function));
//		static assert(is(typeof(base) == function));
		
		base = derived;
		static assert(isCovariantWith!(typeof(derived), typeof(base)));
	}{
		C delegate() derived;
		I delegate() base;
//		static assert(is(typeof(derived) == function));
//		static assert(is(typeof(base) == function));

		base = derived;
		static assert(isCovariantWith!(typeof(derived), typeof(base)));
	}
}

dmd 2.056から関数とデリゲートのcovarianceが考慮されるようになったので,たまたま見つけたisCovariantWithでも判定できるかと思ってやってみたら動かなかった.
isCovariantWith(F,G)のconstraintを消したら動いたけど,あれって必要なのかな?
そもそも,static assert(is(main == function);がfalseなんだけどis(... == function)ってどういうものだったっけ・・・.

typeof(main) == functionだった.

template isCovariantWith(F, G)
    if (is(F == function) && is(G == function) ||
        is(F == delegate) && is(G == delegate) || isFunctionPointer!F && isFunctionPointer!G)

こうかな.

import std.traits;

interface I { I clone(); }
class C : I
{
    override C clone()   // I.clone() の共変オーバーライド
    {
        return new C;
    }
}

void main()
{
	{
		static assert(isCovariantWith!(typeof(C.clone), typeof(I.clone)));
	}{
		C function() derived;
		I function() base;
		base = derived;
		static assert(isCovariantWith!(typeof(*derived), typeof(*base)));
		static assert(isCovariantWith!(typeof(derived), typeof(base)));
		//static assert(isCovariantWith!(typeof(derived), typeof(*base)));
		//static assert(isCovariantWith!(typeof(*derived), typeof(base)));
	}{
		C delegate() derived;
		I delegate() base;
		base = derived;
		static assert(isCovariantWith!(typeof(derived), typeof(base)));
	}{
		C function() derived;
		I delegate() base;
		//base = derived;
		//static assert(isCovariantWith!(typeof(derived), typeof(base)));
		//static assert(isCovariantWith!(typeof(*derived), typeof(base)));
	}
}

デリゲートと関数ポインタで共変の戻り値(covariance)

import std.stdio;

class Base  {}
class Derived : Base {}

void main()
{
    // Covariance
    {
        Base delegate() f = delegate Derived() { return new Derived; };
        writefln("delegate convariance is <%s>", f().toString() == "a.Derived" ? "OK" : "NG");
    }{
        static Derived fp() { return new Derived; }
        Base function() f = &fp;
        writefln("function pointer covariance is <%s>", f().toString() == "a.Derived" ? "OK" : "NG");
    }
    
    // Contravariance
    {
        auto c = new class { void foo(Base){} };
        
        // GOOD
        void delegate(Base) f = &c.foo;
        f(new Base);
        f(new Derived);
        
        // BAD
        //void delegate(Derived) g = &c.foo;
        //g(new Derived);
    }
}
delegate convariance is <OK>
function pointer covariance is <OK>


反変の方はまだダメみたい.

a.d(33): Error: cannot implicitly convert expression (&c.foo) of type void delegate(Base) to void delegate(Derived)

GW

最近,日記らしいことを全然書いていませんでした.


ヘッドフォンのコードに足を引っかけて落として壊してしまったので,
ついにホットボンドを買ってきました.
強度を持たせようと思って盛りすぎたので少しいびつな形になったけど,使用感はまずまず.
これならまだしばらくは使えます.
前からホットボンドが欲しかったんだけど,いざ買うとなると今は特に困ってないからなあ,と思って買いませんでした.
これで色々壊れても直せますね.


母の日だったので,カーネーションをプレゼントしました.喜んでもらえたのかな?
父が仕事で使う長靴が欲しいと言うのでそれも購入.長靴くらいすぐ買えるがな!


最近,家の中で不便なところを探して直していってます.
安価で簡単に改善できるところがたくさんあるので,
ほったらかしにせず注意して見直してます.


さあー明日からまた頑張って恐ろしい職場に行かなきゃ!!><;

スレッドセーフな銀行クラス(2)

すべてのメソッドの内容を synchronized ブロックに含めるのならクラスを synchronized クラスにしてもよい.
synchronized クラスのメンバはそのインスタンスを shared 型で生成しなければ呼び出せないので,この場合には new Bank ではなく new shared(Bank) とする.

import std.stdio;
import core.thread;

synchronized class Bank
{
	private int money_;
	
	void payin(int m)
	{
		money_ += m;
	}
	void payout(int m)
	{
		// お金があるときだけ出金する
		if (money_ - m > 0)
		{
			money_ -= m;
		}
		if (money_ < 0)
		{
			// ここには来ない
			throw new Exception("pay out exception.");
		}
	}
	int money() @property
	{
		return money_;
	}
}

void main()
{
	auto bank = new shared(Bank);
	auto tg = new ThreadGroup;
	bool isRunning = true;
	
	// 100ずつ出金する人
	tg.create = {
		while (isRunning)
		{
			try
			{
				bank.payout(100);
			}
			catch (Exception e)
			{
				isRunning = false; // 両方のスレッドを終了する
				throw e;
			}
		}
	};
	
	// 100ずつ入金する人
	tg.create = {
		while (isRunning)
		{
			bank.payin(100);
		}
	};
	
	// スレッドを回す
	tg.joinAll();
}

スレッドセーフな銀行クラス

適切に synchronized ブロックを使えば利用者側で気をつける必要がなくなる.
クラスメンバの中での synchronized は synchronized (this) と同じ.

import std.stdio;
import core.thread;

class Bank
{
	private int money_;
	
	void payin(int m)
	{
		synchronized
		{
			money_ += m;
		}
	}
	void payout(int m)
	{
		synchronized
		{
			// お金があるときだけ出金する
			if (money_ - m > 0)
			{
				money_ -= m;
			}
		}
		if (money_ < 0)
		{
			// ここには来ない
			throw new Exception("pay out exception.");
		}
	}
	int money() @property
	{
		synchronized
		{
			return money_;
		}
	}
}

void main()
{
	auto bank = new Bank;
	auto tg = new ThreadGroup;
	bool isRunning = true;
	
	// 100ずつ出金する人
	tg.create = {
		while (isRunning)
		{
			try
			{
				bank.payout(100);
			}
			catch (Exception e)
			{
				isRunning = false; // 両方のスレッドを終了する
				throw e;
			}
		}
	};
	
	// 100ずつ入金する人
	tg.create = {
		while (isRunning)
		{
			bank.payin(100);
		}
	};
	
	// スレッドを回す
	tg.joinAll();
}

銀行クラスをスレッドセーフに扱う

どこでどのような競合を起こしうるのか想像するのが難しい.
このようにスレッドセーフに使えるクラスを「スレッドコンパチブルである」という.

import std.stdio;
import core.thread;
import core.sync.mutex;

class Bank
{
	private int money_;
	
	void payin(int m)
	{
		money_ += m;
	}
	void payout(int m)
	{
		money_ -= m;
		if (money_ < 0)
		{
			// ここには来ない
			throw new Exception("pay out exception.");
		}
	}
	int money() @property
	{
		return money_;
	}
}

void main()
{
	auto bank = new Bank;
	auto tg = new ThreadGroup;
	bool isRunning = true;
	auto mutex = new Mutex;
	
	// 100ずつ出金する人
	tg.create = {
		while (isRunning)
		{
			try
			{
				synchronized (mutex)
				{
					if (bank.money >= 100) // 残金を確認して
					{
						foreach (_; 0..10000){} // 異常が起こりやすいように待つ
						// お金があるときだけ出金するはず?
						bank.payout(100);
					}
				}
			}
			catch (Exception e)
			{
				isRunning = false; // 両方のスレッドを終了する
				throw e;
			}
		}
	};
	
	// 100ずつ入金する人
	tg.create = {
		while (isRunning)
		{
			synchronized (mutex)
			{
				bank.payin(100);
			}
		}
	};
	
	// スレッドを回す
	tg.joinAll();
}