News for hackers. Stuff that matters.
Re:Fear of Macros by auvrw on Thursday April 17, 2014 @12:25AM (#7601992)
i don't fear macros, but i am wary of them: when there are only a few macros, it seems as though replacing them with functions makes more sense, even if the syntax is slightly messier. when there are so many macros that you've essentially made an entirely new language, writing a REPL feels like a cleaner separation, even if it is more work.

i would be interested to see links to libraries, particularly clojure libraries, that make heavy but judicious use of macros. it totally makes sense that macros are useful because they capture part of this "code as data" idea that's so central to, esp., lisps. but having more examples of actual problems that they solve would be helpful.

Re:Fear of Macros by Psyonic on Thursday April 17, 2014 @01:25AM (#7602111)
A good example, clojure logging. https://github.com/clojure/tools.logging

They look the same as normal logging function calls, but entirely avoid the issue of "logging guards."

I'll point you at a good link, but basically if you have a lot of calls to logger.debug, logger.trace, etc, and they involve a lot of string conversions, you pay the penalty for those string conversions all the time even when you're logging at warn or higher. This leads many java developers to do the following:

if (LOGGER.isDebugEnabled()) { LOGGER.debug("last node was: " + node); }

... which makes logging significantly heavier visually.

With a macro you are essentially adding syntax, so you can bake the guards into your log statements.

Logging guards: http://www.kdgregory.com/index.php?page=java.logging

Re:Fear of Macros by twic on Thursday April 17, 2014 @08:07AM (#7603067)
Although, for what it's worth, Java programmers solved this quite some time ago by allowing crude lazy evaluation of the string. Logging calls actually look like:

  LOGGER.debug("last node was: {}", node);
Where the parameters are a template string and a varargs of objects. The objects are stringified and substituted into the template only once the logging library determines that the message will actually be used.

In Scala, you just make the parameter to the call a lazy or call-by-name value, and then there's no need to write an explicit template, the language captures the expression which produces the string and defers its execution until it's needed.

Of course, there are many things macros can do which mechanisms like these can't. The choice in language design is between introducing macros, or introducing enough other mechanisms to make macros unnecessary. Introducing macros seems more parsimonious, but given the utter confusion that macros can be used to wreak, it's not a slam dunk.

And, of course, the Scala designers have introduced all these mechanisms and then added macros anyway, because they're crazy.

Re:Fear of Macros by pavelludiq on Thursday April 17, 2014 @04:50AM (#7602581)
My favorite example would have to be CLOS the Common Lisp object system. Although it's a bit hairy in certain places, it essentially transforms a procedural/functional language into on of the most powerful object oriented languages around. Macros play a small, but crucial part of it, subverting the rules of lisp in order to add another dimension to the language.

Another great example might be Postmodern and CLSQL, both of which include SQL DSLs, much better than concatinating strings or muddling around with ORMs. CL's loop macro basically ads an algol like language to lisp(if you dislike loop, there exist lispier alternatives like iterate).

Macros take care of the case between writing a function and writing an interpreter, and with judicious use, they can help build much cleaner abstractions that give a qualitative improvement to a code base.

Re:Fear of Macros by mkremins on Thursday April 17, 2014 @02:10AM (#7602200)
core.async [1] is basically the canonical example of a Clojure library that relies on macros to do its job, although surprisingly few macros actually need to be exposed in the public API. Most notable is the go macro, which performs deep-walking code transformation on its body, permitting clients to write async code in a straightforward, boilerplate-free way.

There's usually a heavy emphasis in the Clojure community on keeping macros as small as possible – the thinking is that any behavior that can be implemented with ordinary functions should be, and most macros should be lightweight wrappers over these functions. This seems to fit together well with what I've observed: functional programming idioms often circumvent some of the more common legacy uses of macros in practice, relegating macros to a still-essential but less prevalent role.

[1] https://github.com/clojure/core.async

Re:Fear of Macros by auvrw on Thursday April 17, 2014 @02:24AM (#7602234)
> the thinking is that any behavior that can be implemented with ordinary functions should be

this is what i was trying to say.

Re:Fear of Macros by stchang on Thursday April 17, 2014 @12:10PM (#7604463)
All of Racket's `#lang` family of languages are implemented with macros on top of core Racket. For example, Scribble, mentioned in another comment, is the documentation language used to author the article, and the Racket docs[1]). Or Slideshow, Racket's programmatic Powerpoint alternative.

Try to add a static type system to Racket or Clojure. Oh but you don't have the ability to change the runtime system. With macros you can do it. See Typed Racket[2] or Typed Clojure[3].

[1]: http://docs.racket-lang.org/ [2]: https://github.com/plt/racket/tree/master/pkgs/typed-racket-... [3]: https://github.com/clojure/core.typed

Re:Fear of Macros by leephillips on Thursday April 17, 2014 @12:48AM (#7602036)
"particularly clojure libraries, that make heavy but judicious use of macros"

Try the Clojure standard libraries. Many central parts of the language like "->>" are macros.

Re:Fear of Macros by auvrw on Thursday April 17, 2014 @02:23AM (#7602231)
oh, yes, indeed, the ->> macro is slick. reminds me of the bind operator in haskell. i don't know why i haven't seen something like it in other lisps. but as you said, that's part of the language.

anyway, should clarify: i'm interested in libraries that define and then use lots of macros in order to solve a specific problem. i'd like to know what problem domains are particularly well suited to the sort of language extension that macros provide.

Re:Fear of Macros by masklinn on Thursday April 17, 2014 @03:05AM (#7602319)
> but as you said, that's part of the language.

Well no since it's a macro. It's part of the standard library, not a special form part of the language.

Re:Fear of Macros by TeMPOraL on Thursday April 17, 2014 @05:37AM (#7602689)
The point of macros is to blur the distinction between what's "built-in" and what's "user-defined" to the point of irrelevancy.
Re:Fear of Macros by greghendershott on Thursday April 17, 2014 @05:24PM (#7606491)
Re:Fear of Macros by davexunit on Thursday April 17, 2014 @09:49AM (#7603490)
I don't know Clojure, but here's a couple of good macro examples in Scheme.

Scheme's SRFI-41[0] implements Streams, which are lazily evaluated lists. A few macros are used in order to introduce lazy evaluation to the language. The Streams API wouldn't be very nice at all if no macros were used.

How about something more basic like the `let` macro? It's something you can't live without.

Whenever you need to control the order of evaluation, macros are what you want. Don't be wary of them. They are wonderful.

[0] http://srfi.schemers.org/srfi-41/srfi-41.html