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.
4 Comments
Hide/Show CommentsJan 22, 2014
Kevin Downey
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
Jun 18, 2014
Christophe Grand
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.)
Jun 23, 2014
Kevin Downey
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
Mar 11, 2015
Ambrose Bonnaire-Sergeant
This also can help vars know exactly the file/line number they were dereferenced from. This information is useful for exporting "typed" functions to "untyped" namespaces, so we can blame exactly which untyped namespace uses a var incorrectly.
Do we get a hook for both the first-order and higher-order invocations? Both would be preferable. I basically want symbol macros.