Questions about Scala macros

89 views
Skip to first unread message

Mike Morearty

unread,
Jan 9, 2013, 7:15:24 PM1/9/13
to scala...@googlegroups.com

I'm just experimenting with Scala macros, and I have some questions.

As a learning exercise, I was trying to write a Scala version of the Clojure macro on this StackOverflow reply: http://stackoverflow.com/a/10435150/179675 , which gives Clojure a C-style "for (a; b; c) ... " loop.

More specifically, that sample defines a macro that takes four (not three) arguments. The first two arguments are sym (the name of a new loop variable to define, which will be local to the loop), and init (its initial value). The other two arguments are check (the second expr in the for parens) and change (the third expr).

The part I can't figure out how to do is sym. The point is that at the point where I am invoking the macro, the variable does not yet exist. The macro is supposed to define it.

In other words, in the end, I want to be able to write some code like this:

// Note, 'i' has not yet been defined above this code
MyMacros.forloop(i, 0, i<10, i++) {
    println(i)
}

I can't figure out how to do it. All I have so far is an empty macro definition:

object MyMacros {
  def forloop(sym: Any, init: Any, check: Boolean, change: Any)
             (loop: Any): Unit = macro forloopImpl

  def forloopImpl(c: Context)(sym: c.Expr[Any],
                              init: c.Expr[Any],
                              check: c.Expr[Boolean],
                              change: c.Expr[Any])
                             (loop: c.Expr[Any]): c.Expr[Unit] = {
    import c.universe._

    reify {
    }
  }
}

That compiles fine, not surprisingly. Then I have an attempt (in a separate .scala file of course) to invoke it, which looks exactly like my first code sample above.

But when I compile the second file, I get this:

scalac -classpath bin -d bin MacroTest.scala
vi mymac    MacroTest.scala:9: error: not found: value i
    MyMacros.forloop(i, 0, i<10, i++) { println(i) }
                     ^
one error found
make: *** [bin/MacroTest.class] Error 1

Since the compiler can't find i (which of course has not yet been defined), it complains.

One thing I tried, on a lark, was to make sym a pass-by-name variable:

def forloop(sym: => Any, init: Any, check: Boolean, change: Any)
           (loop: Any): Unit = macro forloopImpl
  ...

But that resulted in a segmentation fault from the compiler :) (I am using scalac 2.10.0)

Any thoughts?

Paul Butcher

unread,
Jan 10, 2013, 5:26:36 AM1/10/13
to Mike Morearty, scala...@googlegroups.com, Eugene Burmako
What you're trying to create is an anaphoric macro. And I suspect you're out of luck with macros as they currently stand :-(

The problem is that the code that's passed to a macro must typecheck *before* it's passed to the macro. And that can't be true if it depends on a variable that doesn't exist yet.

Eugene - I seem to recall something about you planning to support this kind of thing in a future version of Scala's macros? Can you confirm or refute?

--
paul.butcher->msgCount++

Snetterton, Castle Combe, Cadwell Park...
Who says I have a one track mind?

http://www.paulbutcher.com/
LinkedIn: http://www.linkedin.com/in/paulbutcher
MSN: pa...@paulbutcher.com
AIM: paulrabutcher
Skype: paulrabutcher

Eugene Burmako

unread,
Jan 10, 2013, 5:45:45 AM1/10/13
to Paul Butcher, Mike Morearty, scala-user
Paul is right - this is currently impossible to implement using macros. We plan to eventually experiment with this in untyped macros (see a slide about untyped macros at http://scalamacros.org/news/2012/12/18/macro-paradise.html).

As to a segmentation fault from the compiler, could you provide more details (the snippet which triggers an error, the stack trace)?

Mike Morearty

unread,
Jan 10, 2013, 11:44:02 AM1/10/13
to Eugene Burmako, Paul Butcher, scala-user
Eugene and Paul, thanks for the response.  No worries, this isn't something I need to do; I was just poking around and trying things.

Regarding the segmentation fault, unfortunately I can no longer reproduce it.  It occurs to me now that perhaps it happened because I am using "drip" (https://github.com/flatland/drip , "brew install drip" on OSX), which keeps a JVM around for reuse.  

I realize it is extremely rare for a JVM to produce a segmentation fault (unless there is JNI code).

For what it's worth (but this probably won't be much help):

OS X Mountain Lion 10.8.2

java version "1.6.0_37"
Java(TM) SE Runtime Environment (build 1.6.0_37-b06-434-11M3909)
Java HotSpot(TM) 64-Bit Server VM (build 20.12-b01-434, mixed mode)

The source looked something like this (compiled with "scalac MyMacros.scala"):

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

object MyMacros {
  def forloop(sym: => Any, init: Any, check: Boolean, change: Any)
             (loop: Any): Unit = macro forloopImpl

  def forloopImpl(c: Context)(sym: c.Expr[Any],
                              init: c.Expr[Any],
                              check: c.Expr[Boolean],
                              change: c.Expr[Any])
                             (loop: c.Expr[Any]): c.Expr[Unit] = {
    import c.universe._

    reify {
      loop.splice
    }
  }
}

I don't have a callstack or any more details.  This isn't much to go on, I know.  If I see it again I'll try to gather more details!

- Mike

Reply all
Reply to author
Forward
0 new messages