最後、ちょっと蛇足的に。
これまでに書いたエントリのまとめは、こちらです。
導入編
http://d.hatena.ne.jp/Kazuhira/20130730/1375192075
定義情報取得編 - 1
http://d.hatena.ne.jp/Kazuhira/20130801/1375370390
定義情報取得編 - 2
http://d.hatena.ne.jp/Kazuhira/20130803/1375526971
インスタンス操作編
http://d.hatena.ne.jp/Kazuhira/20130804/1375604912
オマケ
http://d.hatena.ne.jp/Kazuhira/20130804/1375607954
現在(Scala 2.10.2)のScalaのReflectionで、注意しておいた方がいいこと、気になったことを少し。
スレッドセーフ?
現時点のScalaのReflectionは、スレッドセーフではありません。
Thread Safety
http://docs.scala-lang.org/overviews/reflection/thread-safety.html
日本語訳
http://docs.scala-lang.org/ja/overviews/reflection/thread-safety.htm
どうも、リフレクションまわりの初期化がスレッドセーフではないようです。UniverseやType、Symbolなど…。
これが解決されるまでは、ちょっと実戦投入はしづらい感じですね。マクロで使う分には、明示的にスレッドを使わなければきっと大丈夫だと。
この問題は、SI-6240で報告されていて、まだ未解決です。
SI-6240
https://issues.scala-lang.org/browse/SI-6240
Scala 2.10.3では直るのでしょうか?どちらにしても、その時にあんまりAPI変わらないといいなぁ〜。現時点で実験的導入とはいえ。
valを書き換えられる?
これは、Mirrorを使っている時に気付いたのですが、valに対してFieldMirror#setでvalの値を書き換えることができます。
以下、検証コード。
対象のクラス。
class SampleClass { val field: String = "val field" }
valを書き換えるコード。
val instance = new SampleClass require(instance.field == "val field") val runtimeMirror = universe.typeTag[SampleClass].mirror val theType = universe.typeOf[SampleClass] val instanceMirror = runtimeMirror.reflect(instance) val valField = theType.member(universe.newTermName("field")).asMethod val valFieldMirror = instanceMirror.reflectField(valField) valFieldMirror.set("val broken") require(instance.field == "val broken")
何事もなく変わりましたが、こういうもん?
自分はこれが嫌だったので、前のMirrorのまとめではvalに対しては面倒でもgetterを使い
val valField = theType.member(universe.newTermName("valField")).asMethod.getter.asMethod
varに対してはgetterとsetterを使いました。
val varField = theType.member(universe.newTermName("varField")).asMethod val varGetField = varField.getter.asMethod // varのgetter val varSetField = varField.setter.asMethod // varのsetter
valに対するMethodSymbol#getterは、NoSymbolとなりますので。
とりあえず、スレッドセーフ性については直ってくれないかなぁ、と…。