Token trees in macros (processing argument lists) - macros

Currently the only way to add extension methods to a type in another module (even if this module is in a submodule) is to define a new trait and implement it for the type. This is very unwieldy, however, as the number of methods becomes large:
trait Ops {
fn parse_list_item(&self, current_item: ListItemInfo)
-> ParseResult<(Document, ListItemInfo)>;
fn parse_list_item_content(&self) -> ParseResult<Document>;
}
impl<'a> Ops for MarkdownParser<'a> {
fn parse_list_item(&self, current_item: ListItemInfo)
-> ParseResult<(Document, ListItemInfo)> {
// ...
}
fn parse_list_item_content(&self) -> ParseResult<Document> {
// ...
}
}
You have to write method signature twice. If it changes, you also have to update it in multiple places. It also adds a lot of noise.
I though that macros would help, but I don't know how to write a correct macro_rules! pattern for argument lists in functions. Here is what I have so far:
#![feature(macro_rules)]
struct Foo;
macro_rules! ops (
($(fn $name:ident($($args:tt)*) -> $ret:ty $body:block)+) => (
trait Ops {
$(fn $name($($args)*) -> $ret;)+
}
impl Ops for Foo {
$(fn $name($($args)*) -> $ret $body)+
}
)
)
mod ops {
ops! {
fn method1(&self) -> int {
10
}
fn method2(&self, i: int) -> () {
println!("{}", i + self.method1());
}
}
pub fn run_test() {
Foo.method2(22);
}
}
fn main() {
ops::run_test();
}
It fails with rather nasty message:
/tmp/rs/ops/src/main.rs:8:27: 8:31 error: expected type, found token INTERPOLATED(NtTT(ptr::P<ast::TokenTree>{ptr: box TTTok(codemap::Span{lo: codemap::BytePos(337u32), hi: codemap::BytePos(338u32), expn_id: codemap::ExpnId(4294967295u32)}, BINOP(AND))}))
/tmp/rs/ops/src/main.rs:8 $(fn $name($($args)*) -> $ret;)+
^~~~
It probably deserves a bug report as the error message is quite intimidating, however, I don't see another way to pass arguments as is. It seems to be related to this issue, however, I hope there is a workaround like
in this case.
Any suggestions?

Related

Wrapping Methods with a Thunk in Scala

I have several methods in my class, each taking in different parameters and returning different parameters. For each of those methods, I want to wrap them in a common piece of code that would do some time logging. For example., when the method starts, it logs the start time and when it ends, it logs the end time and so on.
I have this method implemented:
def withTimerMetrics(fn: => _) = {
Try(AppMetrics.timer.time()).map(context => {
fn
context.close()
})
}
Where the fn is one of the method that is implemented in my class.
Obviously, I get an unbound wildcard error. Is there a way I could do this? I do not want to use Scala macros for this. Any other ideas?
You have wrong method signature. Try this:
def withTimerMetrics[T](fn: => T) = {
Try(AppMetrics.timer.time()).map(context => {
fn
context.close()
})
}
Not sure, why you wrap time() in Try (is it codahale metrics?), because now your function cannot be timed without changing output. I would say it should be somehow so:
def withTimerMetrics[T](fn: => T): T = {
val c = AppMetrics.timer.time()
try {
fn
} finally {
context.close()
}
}
So you can measure execution time without changing in your application logic.

Scala - Recovering function name

I have this timer object:
object Timed {
def apply[T](fn: => T)(implicit logger: Logger): T =
measureDuration(Thread.currentThread().getStackTrace.last.getMethodName, TimeUnit.MILLISECONDS, fn, logger)
}
That I would like to like this (in another class):
def test(): Unit = {
implicit val logger: Logger = LoggerFactory.getLogger("testTimed")
Timed { someFunction() }
}
AND - I would like to recover the string "someFunction" in Timed.apply to pass instead of the stack's last method's name. Is that even possible?
I tried to look at macros, but got lost pretty quickly. I think this one is going to be a bit of challenge. Any idea?
More details:
Inside Timer.apply, we have only fn, but when we write Timed { someFunction() } there is a function name: someFunction - that string ("someFunction") is what I want to recover and print out.
For cases such as Timed { 2 + 2 } or Timed { x }: we can assume that by convention users would then call Timed("addition") { 2 + 2 } and Timed { x } would be removed in code review. In other words, I am interested only in Timed { someFunction() }.
Short of messing with macros, the best way to get the function name inside Timed.apply is to just pass it in as an argument. E.g.,
Timed("someFunction")(someFunction)

how to get scala method name and class of that method

I have a function which handle retry logic for given function. Inside that function I want to print a debug log with given function name and possibly the class name (Of course caller can pass that information) but I want to know how to get those values without call.
My retry method is below, now I get the methodName as an argument, can I just take it from fn ?
def retry[T](attempts: Int, max: Int, operation: String)(fn: => T): T = {
try {
fn
} catch {
case e : Throwable => {
if (attempts < max) {
val retryAttempt = attempts + 1
Thread.sleep((scala.math.pow(2, retryAttempt) * 2000).toLong)
logger.debug(s"Retrying operation: $operation retryCount $retryAttempt")
retry(retryAttempt, max, operation)(fn)
} else {
throw e
}
}
}
}

Scala Lifting to a thunk

I have a function that wraps the result of another function in a Promise. I wanted to promote this into a lift function so that I could sort of re-use it elsewhere. Here are the original definitions:
val abc = Promise[MyType]()
try {
val suck = abc.success(someOtherFunction(intParam1, intParam2))
} catch {
case ex: Exception => p.failure(ex)
}
So what I eventually did was the following:
def myLiftFunc[X](x: X) (op: => X): Promise[X] = {
val p = Promise[X]()
try {
p.success(op)
} catch {
case NonFatal(ex) =>
p.failure(ex)
}
p
}
How can I re-use this? I mean, the second argument that I pass in should be a thunk so that I could just pass in any function body irrespective of the parameters that function body would require!
When I call the lifted function as:
myLiftFunc(someOtherFunction(intParam1, intParam2))
This is of type Int => Promise[Int], where the someOtherFunction returns an Int. I just want Promise[Int] when I call myLiftFunc!
You might be interested in the Promise.fromTry method. That method uses the Try idiom from scala.util, which is a useful structure that allows you to treat a try...catch statement more like a traditional constructs:
Promise.fromTry { Try { someOtherFunction(intParam1, intParam2) } }
If you wanted to right your own helper (so that the Try part is unnecessary, you could try something like:
def myLiftFunc[X](op: => X): Promise[X] = Promise.fromTry(Try(op))
This would allow you to do:
myLiftFunc { /*arbitrary logic*/ }
myLiftFunc(1 + 4).future.value.get //Success(5)
myLiftFunc(1/0).future.value.get //Failure(java.lang.ArithmeticException: / by zero)

surrounding function for adding context

I am trying to write a function which can add a context to those functions given in parameters.
The idea is here
object example {
def withOne(f : => T) = {
val a = 1 //some context
f
}
def foo() = withOne {
println(a)
}
}
I think the context could be passed in implicit.
The idea is to not have the content of f constraint by the surrounding function f should be able to use the context or not.
For now the only way i seen to do that is like that
object example {
def withOne(f : => Int => T) = {
val a = 1 //some context
f(a)
}
def foo() = withOne { a =>
println(a)
}
}
But this forces to declare a 'a' witch is not obvious for others devs :x
I'm afraid you cannot work around this, since you cannot inject an implicit into a function.
There's a proposal to add this feature in the typelevel/scala fork, but it seems hard to achieve as of today.
My suggestion here is to use proper naming, so that you won't surprise your users. For instance if you provide a method like:
def withConnection[A](f: Connection => A): A = {
try {
val conn = ???
f(conn)
} finally {
conn.close()
}
}
it won't surprise me to do:
withConnection { implicit c =>
// db stuff
}