ふと、型修飾子を組み合わせるとどうなるのか気になったので、調べて見ました。
型修飾子の組み合わせというのは、以下のようなものです。
これらの中で、実際に意味を持つものは少なそうですね・・・ dmdはこれらをどのように扱っているのか、以下のコードで調べて見ました。
import std.typetuple, std.stdio;
template ConstOf(T) { alias const(T) ConstOf; }
template SharedOf(T) { alias shared(T) SharedOf; }
template ImmutableOf(T) { alias immutable(T) ImmutableOf; }
alias QualList = TypeTuple!(ConstOf, SharedOf, ImmutableOf);
enum NameList = ["const", "shared", "immutable"];
struct T{}
void main()
{
foreach(i, Qual1; QualList)
{
foreach(j, Qual2; QualList)
{
writefln("%-25s%s", NameList[i] ~ "(" ~ NameList[j] ~ "(T)):", Qual1!(Qual2!T).stringof);
}
}
}
inoutもあるのですが、関数に絡まない形で使われたinoutがどのような挙動になるのか分からないので、今回は除外しました。 結果は、以下のようになりました。
const(const(T)): const(T)
const(shared(T)): shared(const(T))
const(immutable(T)): immutable(T)
shared(const(T)): shared(const(T))
shared(shared(T)): shared(T)
shared(immutable(T)): immutable(T)
immutable(const(T)): immutable(T)
immutable(shared(T)): immutable(T)
immutable(immutable(T)): immutable(T)
意味のある型修飾子の組み合わせは、shared(const(T))だけのようです。 よくよく考えると、shared(const(T))は、「共有されている値へのconstなview」なので、たしかに意味があります。 共有されてる値を、絶対に変更しないという条件付きで、見に行ってる、という感じですね。 変更がないのであれば、スレッド間で同期を取る必要もなくなります。
一方、shared(immutable(T))は、immutable(T)になってますが、これは当然と言えば当然ですね。 なぜなら、immutable(T)は不変な値なので、sharedをつけて同期を強制する意味が無いからです。
とりあえず、意味のある型修飾子の組み合わせは、shared(const(T))だけという事が分かりました。
担当:美馬(inoutとはいったい……うごごご!!)