2

I have some data source that requires wrapping operations in transactions, which have 2 possible outcomes: success and failure. This approach introduces quite a lot of boilerplate code. What I'd like to do is something like this (the same remains true for failures (something like @txFailure maybe)):

@txSuccess(dataSource)
def writeData(data: Data*) {
  dataSource.write(data)
}

Where @txSuccess is a macro annotation that, after processing will result in this:

def writeData(data: Data*) {
  val tx = dataSource.openTransaction()

  dataSource.write(data)

  tx.success()
  tx.close()
}

As you can see, this approach can prove quite useful, since in this example 75% of code can be eliminated due to it being boilerplate.

Is that possible? If yes, can you give me a nudge in the right direction? If no, what can you recommend in order to achieve something like that?

tkroman
  • 4,811
  • 1
  • 26
  • 46
  • Short answer: yes, it's possible to read the annotation arguments out of `macroApplication`. I know I have an old example around somewhere that I'll post when I have a minute. – Travis Brown Aug 20 '14 at 14:53
  • @TravisBrown, I think I'll be able to post my solution in a couple of hours, so please, can you wait a little? I'd like not to have a temptation to oversee the solution before I'm sure I cannot do it on my own :) – tkroman Aug 20 '14 at 15:41
  • @TravisBrown, here is my github repo: https://github.com/cdshines/txMacro. Could you be so kind as to take a look at what I did and maybe provide me with some useful comments/remarks? (except that one I already have in my TODO) – tkroman Aug 20 '14 at 18:03
  • 1
    That looks pretty good to me, although I'd use quasiquotes instead of the `DefDef` stuff. Also `c.prefix` let's you be a little more concise than `c.macroApplication`—sorry I'd forgotten that earlier. – Travis Brown Aug 20 '14 at 18:51
  • 1
    Specifically, `c.prefix.tree.tail` should give you the arguments. – Travis Brown Aug 20 '14 at 18:52
  • @TravisBrown, thank you. I've changed `c.macroApplication` according to your suggestion, but still left `DefDef` instead of quasiquotes because I couldn't find a way to use quasiquotes more concisely than I use `DefDef` now. Thanks for help, anyway, it's been a good case for me to learn the subject. If you'd like, you can post your code in answers as a reference or whatever, so I could resolve this question. – tkroman Aug 21 '14 at 09:04

1 Answers1

0

It's definitely possible, but you don't necessarily need macros for the task.

Here's a simple solution, which doesn't use macros

object DataOperation {
  def withTransation[T](dataSource: DataSource)(f: () => T): T = {
    val tx = dataSource.openTransation()
    f()
    tx.success()
    tx.close()
  }
}

And use it like

DataOperation.withTransation(dataSource) {
  dataSource.write(data)
}
Gabriele Petronella
  • 106,943
  • 21
  • 217
  • 235
  • This is what I use currently. It's a simple implementation of a loan pattern and I like it as it is, but I'm learning macros and I'd like to write it (even if that will be just for fun). In fact, I'm almost ready to post my working solution myself. – tkroman Aug 20 '14 at 15:39
  • @cdshines I get it. I think a macro is an overkill here (the code would definitely be less readable and maintainable), anyway it's a good way to learn. – Gabriele Petronella Aug 20 '14 at 15:54