2013-06-17 9 views
5
デフマクロ経由で抽象メソッドを実装することは不可能であるように思わ

:これは次のエラーで失敗しと抽象メソッドを実装defのマクロ

import scala.reflect.macros.Context 
import language.experimental.macros 

trait A { 
    def foo(): Unit 
} 

object AImpl { 
    def fooImpl(c: Context)(): c.Expr[Unit] = { 
    import c.universe._ 
    c.Expr[Unit](reify().tree) 
    } 
} 
trait AImpl extends A { 
    def foo(): Unit = macro AImpl.fooImpl 
} 

[error] .../A.scala:17: overriding method foo in trait A of type()Unit; 
[error] macro method foo cannot override an abstract method 
[error] def foo(): Unit = macro AImpl.fooImpl 
[error]  ^

私は​​にそれを削除した場合コンパイルする。しかし明らかに、私はAImplが形質Aを満たすことを望んでいます。これを修正するには?


もう一つの試み:

trait AImpl extends A { 
    def foo(): Unit = bar() 
    def bar(): Unit = macro AImpl.fooImpl 
} 

は、新しいエラーを与える:

[error] macro implementation not found: bar (the most common reason for that is that 
    you cannot use macro implementations in the same compilation run that defines them) 
[error] one error found 
+0

実際に '(a:AImpl).foo()'をマクロとして使用サイトで展開する必要があるか、 (通常の) 'foo()'メソッド? – gourlaysama

答えて

4

は、後で最初にコンパイルマクロとAImplでテストをしたあなたは確かにいますか?あなたの2回目の試行などのフォワーダの方法を使用して

は(2.10.2で)動作するようです:

// first compilation run 

import scala.reflect.macros.Context 
import language.experimental.macros 

trait A { 
    def foo(): Unit 
} 

object AImplMacros { 
    def fooImpl(c: Context)(): c.Expr[Unit] = { 
    import c.universe._ 
    c.Expr[Unit](reify().tree) 
    } 
} 

// second compilation run 

trait AImpl extends A { 
    def foo(): Unit = bar() 
    def bar(): Unit = macro AImplMacros.fooImpl 
} 

// compiles and runs: 

scala> val a = new AnyRef with AImpl 
a: AImpl = [email protected] 

scala> a.foo 

scala> a.bar 
+0

ええ、ええ、2つのコンパイルが必要だとわかりました。また、なぜ私はマクロで抽象メソッドを "実装"できないのかを理解していると思います。なぜなら、マクロ呼び出しはメソッドをマクロ本体に "置き換える"ためです。つまり、あなたのコードで 'bar()'メソッドがなくなり、 'def foo():Unit = {}'が残るようになります。そう、はい、私はこのフォワーダのために行くことができます、または私は構図を使用して(マクロ内から全体の特性を実装する)。 –

4

私はこれが正しいかどうかわからないんだけど、そう、追加的な権威の回答をしてください追加してください。

私は、defマクロがどのように機能するか理解し始めています。問題の間違った仮定は、def bar(): Unit = macro ...が実際にランタイムbarを作成することです。代わりに、それは...よく、マクロを作成するので、そのマクロを呼び出すだけで式が連結されます。

私は2つのことを見ます。戻り値の型はc.Expr[DefDef]になりますが、それが可能であるかどうかはわかりません。おそらくもっと多くの作業が必要です。第2の選択肢は、代わりに、形質全体を生成することである。匿名クラスとして:大きな吸う

object AHolder extends App { 
    val bar: A = AImpl.body 

    bar.foo() 
} 

は、私がそうでなければ、これらのファイルにはないので、SBTとサブプロジェクトを設定する必要があり、次のとおりです。代わりにミックスインの後

import scala.reflect.macros.Context 
import language.experimental.macros 

trait A { 
    def foo(): Unit 
} 

object AImpl { 
    def body: A = macro bodyImpl 
    def bodyImpl(c: Context): c.Expr[A] = { 
    import c.universe._ 
    val r = reify { new A { def foo() { println("schoko")}}} 
    c.Expr[A](r.tree) 
    } 
} 

、あなたは組成を有し、 -/

+1

ああ、私は今あなたがしようとしていたものを見る。マクロは実際にはコールサイト*で展開されインライン化*されているため、実際にメソッドを生成しないため、抽象メソッドを実装またはオーバーライドすることはできません。 – gourlaysama

+0

そうです。回答ありがとうございます! –

+0

'私はsbtを使ってサブプロジェクトをセットアップする必要があります。そうでないと、これらのファイルは同時にコンパイルされません。その理由は:'最も一般的な理由は、 同じコンパイルの実行それはそれらを定義する '? –

関連する問題