Everyone believes that macros (as in C preprocessor and assembly macros) are the Bad Thing and no modern language with any self-respect has them.
Yes, UNIX philosophy explicitly says "Avoid hand-hacking; write programs to write programs when you can" but without a decent macro language, code generation has to be done by an external tool, which makes it obscure and unreadable for anyone beyond the author of the code. (We've actually seen this. OpenAMQ project was havily code generated which then prooved to be almost an inpenetrable barrier for the contributors.)
I think I know what happened: Everyone was scared away be the sheer ugliness and inadequateness of C preprocessor and nobody even tried to do the same thing again and better.
Here are some deficiencies of C macros system, just off the top of my head:
- Why does it have non-C syntax?
- Is it even Turing complete?
- And even if it is, why the hell do I have to define 3 nested macros to do such a basic operation as string concatenation?
- Why are such elementary primitives as __COUNTER__ not in the standard?
But it's too late to fix that.
What about newer languages though?
Perl: Nothing. Python: No macros. Ruby: Nada.
If you are thinking of implementing a new programming language that will take over the world, give humble old macros a chance. Just take care to implement it in a sane way. After all, macro is just a function that returns a string that then gets inserted into the source code.
Martin Sústrik, July 5th, 2015
Nim?
Good to know. I've heard good things about Nim. I should have a look… but there's still Haskell and Rust on my todo list :(
Yeah.. Macroses as well as goto, multiple inheritance and others undeservedly retired just because they have a bad luck to be used improperly.
Rust looks promising in this regard.
Well you still have stuff like Threads, mutable state, MetaClasses, eval, exec… currentframe().f_back.f_locals, etc… Macros are awesome, especially if you disallow "binding" forms (introducing variables). They let you check code at runtime. For example, you can write a macro version of open that can check whether or not files exist at *COMPILE* time not *RUN TIME*. Other types of static analysis are possible. Caching is very important for run-time efficiency, and making a custom static compiler could also be possible.
What would you even use macros for in Python? You can already define functions and classes anywhere, and do pretty much anything you want. C needs them because the language is so restrictive, but I can't think of anything similar in Python.
Specifically, I wanted to generate a group of functions, all with the same prototype, without having to repeat same list of arguments each time.
You can generate functions like that dynamically in Ruby. I have helper functions generated dynamically in: https://github.com/twohlix/database_cached_attribute/blob/master/lib/database_cached_attribute.rb#L62
so when I call
database_cached_attribute :bollocks
database_cached_attribute :silliness
my class ends up with nice to have functions like
invalidate_silliness, only_silliness_changed?, cache_silliness
invalide_bollocks, only_bollocks_changed?, cache_bollocks
etc…
You can do that sort of thing in Python too; it's all dynamic in the end. Even if you were willing to put up with the nastiness though, there could be other drawbacks. For example, if you use mypy to do typechecking, you can't typecheck the functions you're generating at runtime. But if macros had been part of the language, mypy could learn how to expand them.
I'll have to agree with the GP. In Python you simply load the module, insert your functions types and whatever there, and rewrite the name at the global scope.
That is, Python macros are written in Python (and sometimes they are even useful). It also supports goto and multiple inheritance.
I'd argue that Lisp is plenty of inspiration for people to not run away from macros. It's just that we already have a good set of macro oriented languages, so people aren't rushing to replace it.
Python has many great facilities for macros. At the lowest level code can be generated dynamically and integrated in to the running program via eval and exec.
In the std lib namedtuple which builds a class from a textual template and then calls exec to compile it. You can see the generated code by passing verbose=True in the construction function.
At at much higher level macropy gives you full syntactic macros like you would get in a Scheme or Lisp.
If that isn't enough, there is Hy language which is a full Lisp hosted on Python. Full Python semantics with Lisp syntax, including macros.
Perl hasn't got a "standard" preprocessor because it has got a better tool: filters.
A filter is a Perl module which reads the initial source code and produces the Perl code passed to the final Perl interpreter.
This allows everyone to create its own new syntax or DSL in Perl.
See: perldoc Filter::Simple , perldoc Filter::Util::Call
A big problem with languages that allow macros is that they make it very hard to write static analysis tools for them. Having macros also means that the syntax of the language isn't fixed, just look at all the trouble the C preprocessor can cause (#define BEGIN {) or how godawful (La)TeX is. There are real reasons why people have turned away from macros.
You can run the static analysis tools after all the macros have expanded, or before. If you do it before the macros are just function calls. The macros are what allow you to make custom static analysis tools…
Clojure is a modern reincarnation of lisp that has a decent support for macro.
And, macro is fine in the lisp languages.
By the way, here's a cool article why use a python.
https://webcase.studio/blog/why-use-python/
Who are interested, these guys have the more interesting post in their blog.
Post preview:
Close preview