2012-12-02 26 views
38

Więc mam tego makra:statyczny typ powrót Scala makropolecenia

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) 
} 

mówiłem trzy razy, że chcę foo zwrócić Foo, a jednak mogę wykonać następujące czynności (w 2.10. 0-RC3):

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

scala> res0.launchMissiles 
res1: String = launching 

To samo dzieje się, jeśli mogę usunąć parametry typu na obu c.Expr. Jeśli naprawdę chcę się upewnić, że ktokolwiek dzwoni pod numer foo, nie może zobaczyć, że uzyskuje on Bar, muszę dodać przypisanie typu w drzewie.

Jest to całkiem niezłe - oznacza to na przykład, że mogę wskazać makro na schemacie i stworzyć anonimową podklasę klasy Vocabulary z metodami reprezentującymi terminy w słowniku, a te będą dostępne na zwrócony obiekt.

Chciałbym zrozumieć, co dokładnie robię, więc mam kilka pytań. Po pierwsze, jaki jest rzeczywiście typ zwrotu w metodzie foo? Czy jest on dostępny tylko dla (opcjonalnej) dokumentacji? To wyraźnie ogranicza typ zwracany (np, nie mogę go zmienić na Int w tym przypadku), a jeśli usunąć go w całości pojawia się błąd jak poniżej:

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

Ale można zmienić go naAny i nadal otrzymuję statycznie wpisany Bar, gdy zadzwonię pod numer foo.

Po drugie, czy to zachowanie jest gdzieś określone? Wydaje się, że jest to dość elementarny zestaw problemów, ale nie byłem w stanie wyszukać jasnego wyjaśnienia lub dyskusji.

+2

@ som-snytt: Ale nadal oczekiwałbym typu zwrotu na 'foo', aby mieć ostatnie słowo (chociaż cieszę się, że tak nie jest). –

+2

Adnotacja typu zwrotu na 'FooExample.foo' jest tutaj bardzo dziwna. W przeciwnym razie spodziewam się zachowania makr. – drstevens

+0

@drstevens: Zgoda. –

Odpowiedz

19

To zachowanie jest niedookreślone, ale zamierzone, choć może wydawać się mylące. Planujemy rozwinąć rolę typu zwrotu w makro podpisach, ale w tej chwili mam wrażenie, że elastyczność to dobra rzecz.

Czasami zachowanie jest niespójne, np. gdy makro zostanie przechwycone w środku wnioskowania typu, jego statyczny podpis zostanie użyty (np. Foo w twoim przykładzie), a nie typ rzeczywistego rozwinięcia. Dzieje się tak dlatego, że ekspansja makr jest celowo opóźniana, dopóki nie zostanie wykonane wnioskowanie o typie (aby implementacje makr mogły widzieć typy wnioskowane, a nie vars typu). To jest kompromis i niekoniecznie najlepszy, więc planujemy powtórzyć to wkrótce: https://issues.scala-lang.org/browse/SI-6755.

Kolejnym problemem w tym dziale są makra bezwarunkowe. Kiedy typ zwracania niejawnego makra jest ogólny i należy go wywnioskować z żądanego typu niejawnej wartości, występują złe rzeczy. Dzięki temu obecnie nie można używać makr do generowania tagów typu: https://issues.scala-lang.org/browse/SI-5923.

+0

Czy to oznacza, że ​​nie można używać rzeczywistego typu ekspansji w wyszukiwaniu niejawnym, chyba że wyszukiwanie to zostało wykonane bezpośrednio przez samo makro? –

+1

Niemożliwe teraz i prawdopodobnie nie będzie możliwe później. W przeciwnym razie wyszukiwanie niejawne będzie musiało rozszerzyć wszystkie domyślne makra w zakresie. Czy masz na myśli konkretny przypadek użycia? –

+0

Nie, próbuję stworzyć mentalny obraz tego, jak działają rzeczy; c.inferImplicitValue zrobi lewy w większości przypadków, jak sądzę. –