2009-04-15 9 views
109

バイトコードレベルでScalaのパターンマッチングはどのように実装されていますか?バイトコードレベルでScalaでパターンマッチングがどのように実装されていますか?

これは一連のif (x instanceof Foo)構造のようなものですか?パフォーマンスの意味は何ですか?

たとえば、次のコード(Scala By Example 46-48ページ)を使用すると、evalメソッドの同等のJavaコードはどのように見えますか?

abstract class Expr 
case class Number(n: Int) extends Expr 
case class Sum(e1: Expr, e2: Expr) extends Expr 

def eval(e: Expr): Int = e match { 
    case Number(x) => x 
    case Sum(l, r) => eval(l) + eval(r) 
} 

P.S.私はJavaのバイトコードを読むことができるので、バイトコードの表現で十分ですが、他の読者にとっては、Javaコードとどのように見えるかを知る方が良いでしょう。

P.P.S. Scalaがどのように実装されているかについては、書籍Programming in Scalaがこれと同様の質問に答えてくれますか?私は本を​​注文しましたが、まだ到着していません。

+0

このサンプルをコンパイルし、Javaバイトコード逆アセンブラで逆アセンブルしてみませんか? – Zifre

+0

誰かがまず良い答えを出さなければ、おそらくそれをやるでしょう。しかし、今、私はいくつかの睡眠をしたいです。 ;) –

+22

この質問は他の読者には便利です! – djondal

答えて

85

低レベルの逆アセンブラで検討することができますが、短い答えは、それはあなたのようなパターンで行うことができますより多くの場合/述語がパターンに依存するよそ

case Sum(l,r) // instance of check followed by fetching the two arguments and assigning to two variables l and r but see below about custom extractors 
case "hello" // equality check 
case _ : Foo // instance of check 
case x => // assignment to a fresh variable 
case _ => // do nothing, this is the tail else on the if/else 

の束がありますということです"case Foo(45、x)"のようなパターンや組み合わせがありますが、これらは一般的に私が説明したものの論理的拡張です。パターンにはガードを付けることもできます。ガードは述語に対する追加の制約です。また、コンパイラがパターンマッチングを最適化できるケースもあります。たとえば、ケース間に重なりがあると、少し合体するかもしれません。高度なパターンと最適化はコンパイラの作業領域であるため、Scalaの現在および将来のバージョンではバイトコードが大幅に改善されても驚くことはありません。

これ以外にも、Scalaがケースクラスに使用する既定のエクストラクタに加えて、またはその代わりに、独自のカスタムエクストラクタを記述することができます。そうした場合、パターンマッチのコストは、抽出者が行うすべてのコストとなります。よい概観はhttp://lamp.epfl.ch/~emir/written/MatchingObjectsWithPatterns-TR.pdf

70

ジェームス(上)で最もよく言った。しかし、好奇心が強い場合は、逆アセンブルされたバイトコードを調べるのがよいでしょう。 -printオプションを指定してscalacを呼び出すこともできます。これにより、すべてのScala固有の機能が削除されたプログラムが印刷されます。 Scalaの衣服では基本的にJavaです。

def eval(e: Expr): Int = { 
    <synthetic> val temp10: Expr = e; 
    if (temp10.$isInstanceOf[Number]()) 
    temp10.$asInstanceOf[Number]().n() 
    else 
    if (temp10.$isInstanceOf[Sum]()) 
     { 
     <synthetic> val temp13: Sum = temp10.$asInstanceOf[Sum](); 
     Main.this.eval(temp13.e1()).+(Main.this.eval(temp13.e2())) 
     } 
    else 
     throw new MatchError(temp10) 
}; 
28

はバージョン2.8以来、Scalaは@switch注釈があった。ここでは、与えたコードスニペットに関連するscalac -print出力です。目標は、一連の条件付きifステートメントの代わりにtableswitch or lookupswitchにコンパイルされることを確実にすることです。

+5

定期的に@switchを選択するときはいつですか? –

関連する問題