Scala の 無名関数や specialized の命名規則の内部実装に関する話

これについて
Scalaのfor文を掘ってみる
分かる範囲で補足的なもの。versionは2.9.1です

yield処理は、apply$mcII$sp()

このapplyっていうのは無名関数がコンパイルされた際に名前がつくやつですね。
flatMapの引数は無名関数なわけですから、簡単に言うと for の中の <- の数の分くらい無名関数生成されます。また無名関数は内部クラスに変換されるので、内部クラスがどんどんネストして、あんな感じの長いクラスファイル名になるわけです。

そしてこの場合の無名関数は Function1 型です。Function1 型には specialized アノテーションがついてます。specializedアノテーションが付いている場合、(Boxingが起きないように)それぞれの型に応じてメソッドが生成されます。たとえば以下のようにしてみればわかりますが

scala> {x:Int => x}.getClass.getMethods.foreach(println)
public final int $line4.$read$$iw$$iw$$anonfun$1.apply(int)
public final java.lang.Object $line4.$read$$iw$$iw$$anonfun$1.apply(java.lang.Object)
public int $line4.$read$$iw$$iw$$anonfun$1.apply$mcII$sp(int)
public scala.Function1 scala.runtime.AbstractFunction1$mcII$sp.compose(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1$mcII$sp.compose$mcII$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1$mcII$sp.andThen(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1$mcII$sp.andThen$mcII$sp(scala.Function1)
public java.lang.String scala.runtime.AbstractFunction1.toString()
public boolean scala.runtime.AbstractFunction1.apply$mcZD$sp(double)
public double scala.runtime.AbstractFunction1.apply$mcDD$sp(double)
public float scala.runtime.AbstractFunction1.apply$mcFD$sp(double)
public int scala.runtime.AbstractFunction1.apply$mcID$sp(double)
public long scala.runtime.AbstractFunction1.apply$mcJD$sp(double)
public void scala.runtime.AbstractFunction1.apply$mcVD$sp(double)
public boolean scala.runtime.AbstractFunction1.apply$mcZF$sp(float)
public double scala.runtime.AbstractFunction1.apply$mcDF$sp(float)
public float scala.runtime.AbstractFunction1.apply$mcFF$sp(float)
public int scala.runtime.AbstractFunction1.apply$mcIF$sp(float)
public long scala.runtime.AbstractFunction1.apply$mcJF$sp(float)
public void scala.runtime.AbstractFunction1.apply$mcVF$sp(float)
public boolean scala.runtime.AbstractFunction1.apply$mcZI$sp(int)
public double scala.runtime.AbstractFunction1.apply$mcDI$sp(int)
public float scala.runtime.AbstractFunction1.apply$mcFI$sp(int)
public long scala.runtime.AbstractFunction1.apply$mcJI$sp(int)
public void scala.runtime.AbstractFunction1.apply$mcVI$sp(int)
public boolean scala.runtime.AbstractFunction1.apply$mcZJ$sp(long)
public double scala.runtime.AbstractFunction1.apply$mcDJ$sp(long)
public float scala.runtime.AbstractFunction1.apply$mcFJ$sp(long)
public int scala.runtime.AbstractFunction1.apply$mcIJ$sp(long)
public long scala.runtime.AbstractFunction1.apply$mcJJ$sp(long)
public void scala.runtime.AbstractFunction1.apply$mcVJ$sp(long)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcZD$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcDD$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcFD$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcID$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcJD$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcVD$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcZF$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcDF$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcFF$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcIF$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcJF$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcVF$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcZI$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcDI$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcFI$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcJI$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcVI$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcZJ$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcDJ$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcFJ$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcIJ$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcJJ$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.compose$mcVJ$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcZD$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcDD$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcFD$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcID$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcJD$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcVD$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcZF$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcDF$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcFF$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcIF$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcJF$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcVF$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcZI$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcDI$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcFI$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcJI$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcVI$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcZJ$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcDJ$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcFJ$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcIJ$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcJJ$sp(scala.Function1)
public scala.Function1 scala.runtime.AbstractFunction1.andThen$mcVJ$sp(scala.Function1)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

いっぱいメソッドできてます。(おそらく)この mcII の II は 引数が Int で戻り値も Int という意味です。(Intの頭文字のI) そしてこの場合も、{x:Int => x}というものを定義したので

public int $line4.$read$$iw$$iw$$anonfun$1.apply$mcII$sp(int)

となっていますよね?これを

{x:Double => x}

{x:Long => x}

にすれば、msIIではなく、その部分が微妙に違う文字列になるはずです。その後の sp は specialized の略ですかね?ちなみに、実装がこうなっているっていうだけでこのあたりは仕様で決まってるわけではありません。べつに覚える必要ありません。そもそもversionによって変わり得ますし。

あと、stackoverflowするのはまぁJVMのスタックサイズのオプションを変えて起動すれば、それなりに変わるんじゃないかなぁーとおもいます。

それと、あまり自信ないけど適当な予想

以上、べつにあまり役に立たないどうでもいい話・・・(´・ω・`)