When are scala macros expanded?
Jeremy Smith <[email protected]>
| Newsgroups | gmane.comp.lang.scala |
|---|---|
| Message-ID | <[email protected]> |
I am running into an issue with macros being expanded more eagerly than I
expect. I like to describe the actual problem first (rather than what I
have morphed it into) in case I'm just approaching things in completely the
wrong way to begin with, which is likely.
The underlying issue (which I had hoped this use of macros might solve,
since this project was already macro-heavy) is that given a trait that I
wish to implement (and don't control):
trait InterfaceTrait {
def foo(str: String): String
def bar(num: Int): String
}
I want my implementation of foo to require an implicit to be present if it
is called. You cannot simply write:
def foo(str: String)(implicit env: Something): String = ???
Because that wouldn't be considered an implementation of foo from
InterfaceTrait. If you try to do this:
def foo(str: String) = {
val env = implicitly[Something]
...
}
or this:
def _foo(str: String)(implicit env: Something) = ???
def foo(str: String) = _foo(str)
Or any other trick which would materialize the implicit without it being a
method parameter to foo itself - then the implicit Something is required
immediately when the implementation is compiled, *whether or not my foo
implementation is ever called*. Obviously, if my implementation is part of
a library, then this isn't good. And if, as in my case, the implementation
is created by a macro, then:
1. foo may never be called, in which case I don't want the implicit to be
required (since it is never actually used) in order for the code using my
library to compile
2. If foo is called, and the implicit is not present, I want it to fail at
the call site of foo, rather than at the site of the macro expansion (or
what would be the site of the implicitly[Something] call, if the class
definition were not hidden by a macro expansion).
Since my project already uses macros, I thought maybe moving the implicit
resolution into a macro could help solve this. For example, the macro that
creates the implementation could write foo as such:
def foo(str: String) = {
Macros.provideTheImplicit { imp =>
...
}
}
Where Macros.provideTheImplicit is itself a macro-backed function that
resolves the implicit and executes the provided anonymous function, passing
in the resolved implicit.
Finally, I get to the question: I had hoped (I'm not sure why) that
Macros.provideTheImplicit {....} would get expanded by the compiler when a
call to foo appears in code. But instead, the call written by the
expansion is itself expanded immediately, regardless of whether that code
path will ever be reached.
I also tried making provideTheImplicit a method on a class which I
instantiate, and or instantiate lazily. Neither one did what I had hoped.
So the questions are:
1) Can I prevent a macro from being expanded if it never gets called? This
would be an interesting question regardless of whether or not it applies to
my use case.
2) Is there some way I can pull an implicit, without it being a method
parameter, but without the compiler freaking out until an actual call site
occurs? It doesn't have to be a macro solution; that's just the hammer I
was working with at the time.
Thanks for any insight!
Jeremy
--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
For more options, visit https://groups.google.com/d/optout.