Hatena::ブログ(Diary)

NetPenguinの日記 このページをアンテナに追加 RSSフィード

'アニヲタ' 兼 Perfume ファン 兼 'Scala, C/C++, Java プログラマ'
日々の愚痴をつづる日記です。
FTPソフトの NetPenguin とは何の関係もありません。

2010-01-12

[]親トレイトで定義されている val を、子トレイトで override するとインスタンス化に失敗する 15:09 親トレイトで定義されている val を、子トレイトで override するとインスタンス化に失敗するを含むブックマーク 親トレイトで定義されている 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 の場合だけ期待通りに動かないみたいですね。

FelioFelio 2010/01/27 12:30 以前にこの話題をLingrで話したことがあって、id:kmizushima さんが メーリングリストで訊いてくれたことがありました。
http://old.nabble.com/-scala--override-val-in-trait-td20890123.html

結論としてはバグで、2.8で直るようです。

NetPenguinNetPenguin 2010/01/29 00:37 お、そうなんですか。情報ありがとうございます。
2.8 に期待ですね。

トラックバック - 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