2012-12-02 33 views
38

だから私はこのマクロ持っている:静的戻り値の型

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

class Foo 
class Bar extends Foo { def launchMissiles = "launching" } 

object FooExample { 
    def foo: Foo = macro foo_impl 
    def foo_impl(c: Context): c.Expr[Foo] = 
    c.Expr[Foo](c.universe.reify(new Bar).tree) 
} 

を私はfooFooを返すようにしたい三回言ったし、まだ私は2.10に(次の操作を行うことができます。 0-RC3):私はどちらかc.Expr上の型パラメータを削除する場合

scala> FooExample.foo 
res0: Bar = [email protected] 

scala> res0.launchMissiles 
res1: String = launching 

同じことが起こります。もし私が本当にfooと呼んでいる人が誰でも彼らがBarを得ているのを見ることができないようにしたいのであれば、私は木の中に型格を追加しなければなりません。

これは実際にはかなり素敵です。たとえば、ある種のスキーマでマクロを指して、Vocabularyクラスの匿名サブクラスを作成し、ボキャブラリの用語を表すメンバメソッドで作成できます。返されるオブジェクト

私は何をしているのか正確に理解したいと思いますので、いくつか質問があります。まず、fooメソッドの戻り値の型は実際には何ですか? (オプションの)ドキュメンテーションのためだけに入手できますか?これは明らかに(例えば、私はこのケースでIntにそれを変更することはできません)戻り値の型を制約し、私はそれを完全に削除する場合、私はこのようなエラーが出る:

scala> FooExample.foo 
<console>:8: error: type mismatch; 
found : Bar 
required: Nothing 
       FooExample.foo 
         ^

しかし、私はにそれを変更することができますAnyと呼びますが、fooを呼び出すと、静的型付きBarが返されます。

第2に、この動作はどこかで指定されていますか?これはかなり基本的な問題のようですが、私は明確な説明や議論を検索することができませんでした。

+2

@ som-snytt:しかし、私は 'foo'の戻り値の型が最終的な単語を持つことを期待していました。 –

+2

'FooExample.foo'のリターン型アノテーションはここでは非常に奇妙です。これは、そうでなければ、マクロが動作することを期待する方法です。 – drstevens

+0

@drstevens:合意しました。 –

答えて

19

この動作は指定されていませんが、混乱する可能性があります。私たちは、マクロ・シグネチャでのリターン・タイプの役割について詳しく説明しますが、現時点では、柔軟性があると良い気持ちになります。

時には動作が矛盾します。マクロがタイプ推論の途中でキャッチされると、実際の拡張のタイプではなく、その静的シグネチャが使用されます(例:Foo)。これは、型推論が行われるまでマクロ展開が意図的に遅れるためです(マクロ実装では、型変数ではなく推論型が見えるようになります)。これはトレードオフであり、必ずしも最良のものではありませんので、すぐに再検討する予定です:https://issues.scala-lang.org/browse/SI-6755

この部門のもう1つの問題は暗黙のマクロによるものです。暗黙のマクロの戻り値の型が一般的で、暗黙の値の要求された型から推論する必要があるとき、悪いことが起こります。これにより、現在、マクロを使用して型タグを生成することが不可能になります:https://issues.scala-lang.org/browse/SI-5923

+0

これは、その検索がマクロ自体によって明示的に行われない限り、暗黙的な検索で実際の展開の型を使用することはできないということですか? –

+1

現時点では可能ではありません。さもなければ、暗黙的な検索では、スコープ内のすべての暗黙のマクロを熱心に展開する必要があります。特定のユースケースを念頭に置いていますか? –

+0

いいえ、私は物事の仕組みに関する精神的なイメージを形成しようとしています。ほとんどの場合、c.inferImplicitValueがトリックを行います。 –