uehaj's blog

Grな日々 - GroovyとかGrailsとかElmとかRustとかHaskellとかReactとかFregeとかJavaとか -

メタプログラミング機構の考古学

Groovyのメタプログラミング機構にはMetaClassがあります。MOPってやつですね。これがいつ導入されたのか気になって、調べてみました。

codehausのリポジトリから入手できるうちで探した限り最古のgroovyのソース(11-May-2004 14:59 211K)をダウンロードして中を見てみると、

$ cd /tool/groovy-1.0-beta-1
$ find . -name '*Meta*' -print
./src/main/groovy/lang/MetaClass.java
./src/main/groovy/lang/MetaClassRegistry.java
./src/main/org/codehaus/groovy/ast/MetadataNode.java
./src/test/org/codehaus/groovy/classgen/MetaClassTest.groovy

のようにメタクラス関係のクラスがそろっています。1.0-beta1の
MetaClass.javaに定義されているメソッドは以下のとおり(11個)

    List getMethods(String name)
    List getStaticMethods(String name)
    Object invokeMethod(Object object, String methodName, Object arguments)
    Object invokeMethod(Object object, String methodName, Object[] arguments)
    Object invokeStaticMethod(Object object, String methodName,Object[] arguments)
    Object invokeConstructor(Object[] arguments)
    List getNewStaticInstanceMethods(String methodName)
    Object getProperty(final Object object, final String property)
    void setProperty(Object object, String property, Object newValue)
    ClassNode getClassNode()
    Object invoke(Object object, Method method, Object[] arguments)

比較のため、Groovy 1.8のMetaClass.javaを見てみると、以下の14個のメソッドが定義されています。

    Object invokeMethod(Class sender, Object receiver, String methodName, Object[] arguments, boolean isCallToSuper, boolean fromInsideClass)
    Object getProperty(Class sender, Object receiver, String property, boolean isCallToSuper, boolean fromInsideClass)
    void setProperty(Class sender, Object receiver, String property, Object value, boolean isCallToSuper, boolean fromInsideClass)
    Object invokeMissingMethod(Object instance, String methodName, Object[] arguments)
    Object invokeMissingProperty(Object instance, String propertyName, Object optionalValue, boolean isGetter)
    Object getAttribute(Class sender, Object receiver, String messageName, boolean useSuper)
    void setAttribute(Class sender, Object receiver, String messageName, Object messageValue, boolean useSuper, boolean fromInsideClass)
    void initialize()
    List<MetaProperty> getProperties()
    List<MetaMethod> getMethods()
    ClassNode getClassNode()
    List<MetaMethod> getMetaMethods()
    int selectConstructorAndTransformArguments(int numberOfConstructors, Object[] arguments)
    MetaMethod pickMethod(String methodName, Class[] arguments)

1.0-betaのころはMetaClassはクラス、1.8はインターフェースになっていたり、1.8ジェネリクスが使われているなど、多少様相は変わってますが、同じ機構ですね。

「ExpandoMetaClass」が比較的最近導入された、というとうことや、GinA本にはメタクラスについての記述があまりない、というとことから、メタクラスは割かし新しいものかと思っていたら、そうでもない(確認できる限り最古レベル)ということがわかりました。

また、同種のメソッド追加機構である「Category」の機構はどうかと調べてみると、

$ cd /tool/groovy-1.0-beta-1/
$ find . -name '*Category*' -print

1.0 beta1にはありませんでした。適当に時代をすすめて

 groovy-1.0-jsr-06-src.zip          28-Jun-2006 09:01  1.6M

らへんには

$ cd ../groovy-1.0-jsr-06-src/
$ find . -name '*Category*' -print
./src/main/groovy/servlet/ServletCategory.java
./src/main/groovy/xml/dom/DOMCategory.java
./src/main/org/codehaus/groovy/runtime/GroovyCategorySupport.java
./src/test/groovy/CategoryTest.groovy
./src/test/org/codehaus/groovy/runtime/GroovyCategoryTest.groovy

ができています。カテゴリとメタクラスのどっちが古いかというと、メタクラスの方が古いんですね。(これを意外に思うのは私だけ?)

なお、DefaultGroovyMethods.javaは、1.0-beta-1のGroovyから存在していました。

Groovy/Grailsのソースツリーの変遷をFlashアニメーションか動画で可視化したものがあったんだけど、どこだったっけ・・
というところで電車がつきそうなので区切りとします。