Hot answers tagged

29

Many Lispers will tell you that what makes Lisp special is homoiconicity, which means that the code's syntax is represented using the same data structures as other data. For example, here's a simple function (using Scheme syntax) for calculating the hypotenuse of a right-angled triangle with the given side lengths: (define (hypot x y) (sqrt (+ (square x) (...


23

The macro is (putatively) more efficient, as it doesn't involve a function call. It can be optimised more easily, as it just involves a pointer offset lookup. The function call allows linking against the same library even if the program was compiled without the macro definition - if it was compiled with a different header, or just with a rogue declaration ...


23

A dissenting opinion: Lisp's homoiconicity is far less of a useful thing than most Lisp fans would have you believe. To understand syntactic macros, it's important to understand compilers. The job of a compiler is to turn human-readable code into executable code. From a very high-level perspective, this has two overall phases: parsing and code generation....


19

Scala makes this possible too (in fact it was consciously designed to support the definition of new language constructs and even complete DSLs). Apart from higher-order functions, lambdas and currying, which are common in functional languages, there are some special language features here to enable this*: no operators - everything is a function, but ...


19

Sure, if you're OK with using macros in the first place, then defining a parametrized one rather than keep repeating the same conditional code is certainly preferable by any measure of good coding. Should you use macros at all? In my view you should, since it's accepted practice in C, and any macro-less solution would require at least something being ...


18

I mostly use macros for adding time-saving new language constructs, that would otherwise require a bunch of boilerplate code. For example, I recently found myself wanting an imperative for-loop similar to C++/Java. However, being a functional language, Clojure didn't come with one out of the box. So I just implemented it as a macro: (defmacro for-loop [[...


17

From http://www.jslint.com/chistory.html ("The Development of the C Language" by Dennis M. Ritchie): Many other changes occurred around 1972-3, but the most important was the introduction of the preprocessor, partly at the urging of Alan Snyder [Snyder 74], but also in recognition of the utility of the the file-inclusion mechanisms available in BCPL and ...


16

A decorator is basically just a function. Example in Common Lisp: (defun attributes (keywords function) (loop for (key value) in keywords do (setf (get function key) value)) function) In above the function is a symbol (which would be returned by DEFUN) and we put the attributes on the symbol's property list. Now we can write it around a ...


15

Take a look at this posting by Matthias Felleisen to the LL1 discuss list in 2002. He suggests three main uses for macros: Data sublanguages: I can write simple-looking expressions and create complex nested lists/arrays/tables with quote, unquote, etc. neatly dressed up with macros. Binding constructs: I can introduce new binding constructs with ...


13

What sorts of things do people actually end up doing with macros? Writing language extensions or DSL's. To get a feel for this in Lisp-like languages, study Racket, which has several language variants: Typed Racket, R6RS, and Datalog. See also the Boo language, which gives you access to the compiler pipeline for the specific purpose of creating Domain-...


13

Haskell Haskell has "Template Haskell" as well as "Quasiquotation": http://www.haskell.org/haskellwiki/Template_Haskell http://www.haskell.org/haskellwiki/Quasiquotation These features allow users to dramatically add to the syntax of the language outside of normal means. These are resolved at compile time as well, which I think is a big must (for ...


13

There's an element of personal preference here, but in C++ I prefer to do this in the header file: #ifdef _DEBUG void DebugMessage(...); #else inline void DebugMessage(...) {} #endif So that the function is inlined away in release builds, but is a proper function in the debug build so you can have proper type checking, sensible error messages, etc. ...


12

Tcl has a long history of supporting extensible syntax. For example, here's the implementation of a loop that iterates three variables (until stopped) over the cardinals, their squares and their cubes: proc loopCard23 {cardinalVar squareVar cubeVar body} { upvar 1 $cardinalVar cardinal $squareVar square $cubeVar cube # We borrow a 'for' loop for ...


12

As a rule, you should only use macros, when a better alternative does not exist. They should not be used to generate code; you should simply write the code instead (if the code is type-agnostic, write a template instead). They should not be used to define constants; constants should be defined using one of these: (static) constexpr/const variables, ...


12

Don't do this. Using macros to reconfigure the language like this is like writing in slang. One or two instances might not seem so bad to someone has to read it (including yourself) but every time you do it you make it that much more likely that the 'well what does that mean' effect happens. You're needlessly obscuring your code, adding a layer of mental ...


12

You are confusing two different concepts in your question. Macros are not about compiling code at runtime. They are the exact opposite: they are about running code at compile time. So, in this case, the problem is the opposite one: it's not about making the compiler part of the program, rather it is about making the macro-program part of the compiler. You ...


11

Version control systems are those systems that allows you to capture changes and create a history for files. That's their purpose and the main reason for which they were created. Therefore if you would like to record changes you should use a version control system, any one out there will do. Nevertheless you should still make and informed decision, and pick ...


11

Using macros to create code that's syntactically identical to C but semantically different is almost always evil, especially in an unsafe language like C where the fact that something compiles in no way guarantees it actually has defined behavior at run time. If you must use a macro for something, you generally want to make it clear that a macro is being ...


11

I currently work on a code base that has classes created with these types of macros. I would strongly discourage doing things this way because if anything goes wrong in the future with any of the macro-ized code it's impossible to debug. It's extremely difficult to change the class in any way. And the macros will likely get manually expanded in the future as ...


10

This is partly a question of semantics. The basic idea of Lisp is that the program is data that can itself be manipulated. Commonly-used languages in the Lisp family, like Scheme, don't really let you add new syntax in the parser sense; it's all just space-delimited parenthesized lists. It's just that since the core syntax does so little, you can make almost ...


10

Byte code weaving and macros are two different things. Byte code weaving is a way to intercept function calls, so that you can inject some sort of functionality (generally a cross-cutting concern such as logging) into a function call, either before or after the function is executed. Byte code weaving is done at the byte code level, which means that it ...


10

Macros in both C and C++ are a text replacement mechanism. Because of that, you can't define a macro in one source file and use it in a different source file. What you can do is define a macro in a header file and include that header in both C and C++ source files where you want to use that macro. Such a header would need to contain only code that comes ...


10

The Lisp family of languages is a fuzzy concept. The key aspects seems to be Support for functional programming Macros Homoiconic (The text <=> The AST, eg Lisp's love of parens) Dynamically typed Garbage Collected The big place where Scala falls down in is 3. Scala is hilariously not homoiconic and this is not a bad thing necessarily. It does have one ...


10

When are macros idiomatic and when should they be avoided? Macros are idiomatic only when there is no alternative to their use. Examples are include guards (they are the only portable form), embedded domain-specific languages, special compiler support not available through other language features (embedding built-in macros like __FILE__, stringifying and ...


9

Lisp macros combine a few distinct properties: Macros define new syntax ↔ they use source-code as input Macros usually are run at compile-time Macros generate source-code The best applications make use of all of those aspects. Probably the most-well known example is the (loop …) in Common Lisp, it wouldn't be anywhere close to its ...


9

A typical "compiling lisp" will include the compiler in a bundled image. Furthermore, most (although not all) function calls are done through symbol indirections (basically, when the compiler sees (+ a b), it emits code to "find symbol +", then "call the function it points to"). This means that function re-definition during program execution is possible by ...


8

Rebol sounds almost like what you're describing, but a bit sideways. Rather than define specific syntax, everything in Rebol is a function call - there are no keywords. (Yes, you can redefine if and while if you truly desire to). For example, this is an if statement: if now/time < 12:00 [print "Morning"] if is a function that takes 2 arguments: a ...


8

In Python (the language) the decorators cannot modify the function, only wrap it, so they are definitely far less powerful than lisp macros. In CPython (the interpreter) the decorators can modify the function because they have access to the bytecode, but the function is compiled first and than can be fiddled with by the decorator, so it's not possible to ...


8

macros have a very different meaning in C (or C++) than e.g. in Common Lisp or Scheme (or some homoiconic programming language). In particular, in Lisp or Scheme you can have macros with some local binding scope. In C or C++ the scope is textual, always from the #define till the end of translation unit or some #undef. And C/C++ macros cannot define other ...


Only top voted, non community-wiki answers of a minimum length are eligible