日々の愚痴をつづる日記です。
FTPソフトの NetPenguin とは何の関係もありません。
2010-01-12
■[Scala]親トレイトで定義されている val を、子トレイトで override するとインスタンス化に失敗する

子側のトレイトで親の val を override すると、コンパイルは成功するにも関わらず、実行時に ClassFormatError が出ます。
以下は現象を再現させるコード。
trait Base { val value: String = "base" } trait Child extends Base { override val value: String = "child" } object OverrideTraitSample { def main(args: Array[String]) { val target = new AnyRef with Child println(target.value) } }
これをコンパイル&実行した結果は以下。
C:\development\workspaces\sandbox\scala-sandbox\src>scalac OverrideTraitSample.scala C:\development\workspaces\sandbox\scala-sandbox\src>scala OverrideTraitSample java.lang.ClassFormatError: Duplicate method name&signature in class file OverrideTraitSample$$anon$1 at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:616) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124) at java.net.URLClassLoader.defineClass(URLClassLoader.java:260) at java.net.URLClassLoader.access$000(URLClassLoader.java:56) at java.net.URLClassLoader$1.run(URLClassLoader.java:195) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:303) at java.lang.ClassLoader.loadClass(ClassLoader.java:248) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:316) at OverrideTraitSample$.main(OverrideTraitSample.scala:11) at OverrideTraitSample.main(OverrideTraitSample.scala) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75) at scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:49) at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74) at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:154) at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala) C:\development\workspaces\sandbox\scala-sandbox\src>
ちなみに使用した scala のバージョンは 2.7.7 final です。
trait ではなく、無名クラスで override してみた場合、ClassFormatError は出ないですが、そもそも override 出来ていません :-P
無名クラスで override した例は以下。
// 〜trait Base は省略〜 object OverrideTraitSample { def main(args: Array[String]) { //val target = new AnyRef with Child val target = new Base { override val value = "anon" } println(target.value) } }
コンパイル&実行結果は以下。
C:\development\workspaces\sandbox\scala-sandbox\src>scalac OverrideTraitSample.scala C:\development\workspaces\sandbox\scala-sandbox\src>scala OverrideTraitSample base C:\development\workspaces\sandbox\scala-sandbox\src>
val を override 出来ていないため、"anon" ではなく、"base" が出力されている。
そもそも val は override できないのか・・・?
追記(2010/01/13)
ちょろっと仕様書の中をさがしてみましたが、trait の val は override 出来ないといった記述は発見できず。
ワークアラウンドですが、val ではなく def で定義しておけば期待どおりの結果になります。
trait Base { //val value: String = "base" def value: String = "base" } trait Child extends Base { //override val value: String = "child" override def value: String = "child" } object OverrideTraitSample { def main(args: Array[String]) { val target = new AnyRef with Child println(target.value) } }
コンパイル&実行。
C:\development\workspaces\sandbox\scala-sandbox\src>scalac OverrideTraitSample.scala C:\development\workspaces\sandbox\scala-sandbox\src>scala OverrideTraitSample child C:\development\workspaces\sandbox\scala-sandbox\src>
ちなみに Base と Child の両方を class にしても期待通り動きます。trait の場合だけ期待通りに動かないみたいですね。
トラックバック - http://d.hatena.ne.jp/NetPenguin/20100112
2004 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 12 |
2008 | 01 | 03 | 04 | 06 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 04 | 11 | 12 |
2011 | 01 | 02 | 03 | 10 |
PV:257504
2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 12 |
2008 | 01 | 03 | 04 | 06 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 04 | 11 | 12 |
2011 | 01 | 02 | 03 | 10 |
http://old.nabble.com/-scala--override-val-in-trait-td20890123.html
結論としてはバグで、2.8で直るようです。
2.8 に期待ですね。