インスタンス毎のメタクラス って強力過ぎ!

コメントにて紹介して頂いた、次の記事を読んで衝撃を受けました。
インスタンスごとのメタクラスを使っての「電卓を作ろう」2番煎じバージョン - uehaj's blog
「インスタンスごとのメタクラス」の活用法 - uehaj's blog
どうも、型だけではなくインスタンス 単位でも拡張出来るそうです。載っていた例で取り上げると、
String って型に IsSymbol ってプロパティを追加し、false を返す様にする。
んで、特定の String インスタンスだけ、IsSymbol プロパティ を上書きして true を返す。


型で既定値を決めて、インスタンス毎に個別の値に差し替えられるって、継承して オーバーライド するような感じ?
しかも String って intern 出来るから、同じインスタンスを参照する事も結構簡単に出来てしまう。この発想凄いな〜。


ちなみに、.NET では 拡張メソッドっていう機能で、型に対しては追加のメソッドを付与出来るように「見える」機能があります。こんな感じ

using System;

static class StringExtension
{
  public static bool IsSymbol(this string source) // String 型に IsSymbol っていうメソッドを拡張。
  {
    return source == "Symbol";
  }
}
class Program
{
  static void Main(string[] args)
  {
    string シンボル = "Symbol";
    string シンボルじゃない = "じゃあ何よ?";

    // 拡張したメソッドを呼んでいる
    Console.WriteLine(シンボル.IsSymbol()); 
    Console.WriteLine(シンボルじゃない.IsSymbol());
  }
}

MSDN 拡張メソッド (C# プログラミング ガイド)から引用

コードでは、インスタンス メソッドの構文を使用して拡張メソッドを呼び出します。ただし、コンパイラが生成する中間言語 (IL: Intermediate Language) により、コードは静的メソッドに対する呼び出しに変換されます。したがって、カプセル化の原則には実質的に違反していません。実際に、拡張メソッドは、それらが拡張している型のプライベート変数にはアクセスできません。

って事なので、内部的にはこんな感じに変換されてる。

string シンボル = "Symbol";
string シンボルじゃない = "じゃあ何よ?";

// 拡張したメソッドを呼んでいる
Console.WriteLine(StringExtension.IsSymbol(シンボル)); 
Console.WriteLine(StringExtension.IsSymbol(シンボルじゃない));

つまり、実際に型を拡張してるんじゃなくて、そういう風に書けるだけの糖衣構文(シンタックスシュガー)のはずです。
なので、上で取り上げた Groovy のインスタンス毎に動きを差し替えるとかは出来ないかなと。


※個人的な感想
使い過ぎると可読性が低くなるんじゃないかなって思う。object 指向で書かれたコードもそうだなぁって思うんだけど、
ぱっと見は何やってるかどんな事をしたいかが一目瞭然なんだけど、実際どんな処理をしているのかを調べる場合大変だったりしませんか?
スキル(慣れ?)があれば、可能なんだろうけど無いと間違った解釈をしてしまいそうになる。
インスタンスの生成箇所だって、単純に new するんじゃなくて Factory やら Container やらから取り出して、どんな型のインスタンスが返ってくるんだよと調べようとすると、設定ファイルとか見ないとダメでとか…。