Okay, we all know why macros are evil and why no one likes them. What I would like to present are reasons why I think Kotlin should have them anyway. Not maybe as a tool for everyday use, but as a set of high powered tools when nothing else works. The way I would implement them is the same way it is done in Nemerle (little known fantastic language for .net), as compiler plug-ins. IDE should be able to expand every macro to see generated code. The principal reasons for macro systems are:
(1) Everyone will be doing it anyway. Java doesn’t have macro system so everyone is writing those horrible code generators. Why let people do it in ad-hoc way that IDE doesn’t support and no one else can understand when we can create cannonical code generation tool? You can say that Kotlin won’t be as bad because it has less bloat and I would be inclined to agree but nothing is bloat free and people will want to simplify repetative tasks.
(2) There are some very good use cases. Macro could log in to a relational database at compile time and check you SQL queries to see if all tables and fields really exist. Also, writing most design patterns could be automated via macros. I know IDE can automate design patterns as well but when it does so it generates code which increases LOC and boilerplate. Macros, on the other hand, generate code on compile time so it is not as visible (but you could still expand macro if you want to know what it outputs.) The cancer that is killing Java is not the lack of any specific feature but boilerplate, so I am all for radical steps to prevent boilerplate.
(3) As one wag put it, programming is all about automating repetative task. Macros are about automating writing code. Therefore programmers should support macros.
Compiler plugins are definitely on the table. Altering language syntax )a la Nemerle) is most likely not, but even without it one can do alot. See Scala.
I don’t really need to be able to alter syntax, but what I would like to have is some form of general nested sytax that I can use for code generation. LISP, of course has S-expressions. Although most languages don’t have macros, Javascript has JSON that could be used for same purpose. XML could also work in theory but it is too verbose in practice. I believe Kotlin needs something like that. Perhaps we can use Builders to assist with code generation? Consider this example:
sql_macro( sql{ select{ fields{“id”, “name”, “address”, “age”} from{“users”} where{ “address =”, address } } } ) // I am not sure if this is correct Builder syntax but you get the idea
At compile time, macro should replace this with the statement:
sql("SELECT id, name, address, age FROM users WHERE adress = '${escape_quotes(address)}' ")
It should then log in to database to check if query makes sense and then let it compile.
I would also like to be able to use annotations as markers for AST transformation. When compiler sees some specific annotation it should transform code in specified way. For example when you put ‘singleton’ annotation in front of class declaration, compiler should add all code necessary to convert class to singleton pattern (I know that you don’t really need singleton pattern when you have functions.)
Finally, I think Kotlin should also support python-like triple quotes so you can add any string you want if you are so inclined.
Is any of this stuff planned?
It should alse be noted that Scala added macro system some time ago, although I don’t know what it can do syntax-vise. Resistance is futile .
Do we then basically agree what macros should and should not be able to do:
Yes to macros as compiler plug-ins.
Yes to tree syntax (builders, in this case) as a way to generate code, as in my SQL example above (I edited it slightly, maybe you would want to take a look again).
Yes to macro annotations
Yes to AST manipulation
Yes to code generation
No to custom syntax
Is this basically the way it is going to be? Sorry if I annoy you, I am just trying to pinpoint exactly what is planned.
Another use-case for macros: implementing (de)serialization of data classes into things like Android’s Parcel. Delegates aren’t powerful enough to do this concisely.
From what I’ve seen, the standard approach is to either do it by hand, or use an IDE code generator plugin. The latter is terrible compared to a compile-time code generator, because it adds noise to the code that I rarely want to see, and I must remember to regenerate whenever the hand-written code changes. And what happens when the generator is improved? I have to go and find all the places I used the code generator and run it again.