kmizuの日記

プログラミングや形式言語に関係のあることを書いたり書かなかったり。

class定義/object定義からの脱出

ささださんの日記の

http://arton.no-ip.info/diary/20080607.html#p01 を見て,Ruby のクラス文からの脱出方法を思い出した.わかる人,居ます? class 文実行中に抜けるの.たとえば,条件次第ではその後のメソッド定義はしない,とか.

http://www.atdot.net/~ko1/diary/200806.html#d07

を見て、ふと、Scalaではclass定義/object定義中に直接式を書くことができるが、return式を書くとどうなるのだろうと思い、実験してみた(Rubyと違い、動的にメソッドを定義するわけではないので、途中までしかメソッドが定義されないということはあり得ないだろうけど)。

まずは、こんなコード。

def f :Int = {
  object A {
    return 200
  }
  100
}
println(f)

実行結果。

100

まあ、Aが評価されてないから当然か。では、次のようなコードだとどうだろう。

def f :Int = {
  object A {
    return 200
  }
  A
  100
}
println(f)

実行しようとすると、java.lang.VerifyErrorで落ちた。どうも、スタックトレース(スタックトレースは無関係なので修正)エラーメッセージを見るに、コンストラクタ中(=JVMレベルでは、返り値がvoidのメソッド)で、intをreturnするようなコードを吐いてるのが原因のようだ。仕様的にどうなるべきなのかはわからないが、とりあえずコンパイラのバグだな。

java.lang.VerifyError: (class: Main$A$2$, method: <init> signature: ()V) Wrong return type in function
	at Main$.A$1((virtual file):5)
	at Main$.f$1((virtual file):8)
	at Main$.main((virtual file):11)
	at Main.main((virtual file))
	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.ScriptRunner$.scala$tools$nsc$ScriptRunner$$runCompiled(ScriptRunner.scala:372)
	at scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scala:399)
	at scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scala:398)
	at scala.tools.nsc.ScriptRunner$.withCompiledScript(ScriptRunner.scala:346)
	at scala.tools.nsc.ScriptRunner$.runScript(ScriptRunner.scala:398)
	at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:176)
	at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

では、クラス定義の方はどうだろうか。これも、object定義の方と同じような結果になりそうな気がするが…。

def f :Int = {
  class A {
    return 200
  }
  new A
  100
}
println(f)

実行しようとすると、やはり予想通りjava.lang.VerifyErrorで落ちた。スタックトレースエラーメッセージからすると、おそらくobject定義の場合と原因は同じだろうなあ。

java.lang.VerifyError: (class: Main$A$1, method: <init> signature: ()V) Wrong return type in function
	at Main$.f$1((virtual file):8)
	at Main$.main((virtual file):11)
	at Main.main((virtual file))
	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.ScriptRunner$.scala$tools$nsc$ScriptRunner$$runCompiled(ScriptRunner.scala:372)
	at scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scala:399)
	at scala.tools.nsc.ScriptRunner$$anonfun$runScript$1.apply(ScriptRunner.scala:398)
	at scala.tools.nsc.ScriptRunner$.withCompiledScript(ScriptRunner.scala:346)
	at scala.tools.nsc.ScriptRunner$.runScript(ScriptRunner.scala:398)
	at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:176)
	at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

2008/06/10追記:
今更だけどバグ報告しておいた(Ticket #1033)