Skip to end of metadata
Go to start of metadata

Problem

For performance, it is sometimes useful to provide inlined code transformations that can be performed during compilation and expanded at the point of use. 

Examples:

1) Optimization for constants. Given a square function, it would be useful to have the compiler perform the square operation at compile time and inline the result in the case where it's called with a constant. 

  (square 3)  could be evaluated and replaced with 9 in the compiled code.

  (map square xs)  would still need to be compiled as a function invocation.

2) Inlining calls to internal Java functions.

3) Optimization for particular arities.

 

Constraints

The following constraints should be considered:

  • If inlining is not possible, a fallback function should be available instead.
  • Inlined functions should be usable as higher-order functions.

Proposal

Compiler macros (from Common Lisp) are the proposed solution to this issue.

Alternatives

The existing implementation in Clojure is definline, which has issues in being used as a higher-order function.

References

Labels:
  1. Jan 22, 2014

    interesting to think on, according to the above link describing common lisp compiler macros, compiler macros are not recursively expanded like macros are.

     

    the only glaring difference between compiler macros and definline seems to be the surface syntax, and definline is sugar on putting values in slots on the var metadata, so it could be given a similar syntax to cl's compiler macros pretty easily

  2. Jun 18, 2014

    One difference between evaluation and macroexpansion is that they occur in opposite directions (top-to-bottom vs bottom-to-top). Both approachs (existing inlines and compiler macros) wouldn't offer the ability to simplify (square (square 3)) into 81.

    If this feature is to optimize regular functions then why not perform expansion on each elements before performing expansion of the whole form? (Thus following evaluation order.)

    1. Jun 23, 2014

      the most symmetric would be something like clojure.walk/walk, expanding on the way in then also on the way out, so each macro can run before it's arguments have been expanding and after