https://github.com/serde-rs/serde
Macros don't need to be as simple to use as in lisps to be useful - the rare library like serialization that can really benefit from them can be worth the language feature
A double edged sword, that! Sometimes the end result with things like macros, is that it so seamless, that there is precious little to figure out what went wrong. Often, if your nifty new facility seems magic, its bugs are going to seem doubly magic. Not too long ago, I had to debug an exception for which no source code existed. It only existed as the confluence of 3 C++ templates.
Codegen on the other hand makes an implementation detail a maintenance cost for the user of the library.
I've heard veteran programmers say that there should be a separation of labor when it comes to libraries. Only certain people make good library writers, in the same way that only certain people make excellent musical accompanists. To be an excellent accompanist, the accompanist should have some sense of what it's like to be the lead. (So should themselves be able to take the lead.) The accompanist should have the perspective to not let his ego get in the way. The accompanist should be giving the lead what she wants, but modulated through their own expertise and sense of taste. (As opposed to mindlessly always giving everything asked for.)
If there is a separation of responsibility, why would codegen be such a burden? If the library has to change so often, perhaps the responsibilities aren't distributed optimally?
I'm the first to admit that macros have downsides compared to not having them in the language, but ease of debugging generated code isn't one of those downsides.
That's because quasiquote and similar operators let you debug code, not code that generates code.
What I've found is that you can debug the generated code to debug the code generator. Code generators shouldn't be used to do something terribly complicated. I'd agree with you that code generators doing complicated things is a code smell. Leave those to native syntax, provided it's not as badly thought out as templates.
I'd argue that those aren't first class macros. C macros are just source manipulators, and C++ templates (I'm not super experienced with them so forgive come if I'm way off) don't really manipulate the AST, it's more a type system with compile time resolution.
First class macros generally contain the same logic as a reflection based approach, but they execute at compile-time and memoize the result. If you can debug compilation (which languages with first class macros generally support), then debugging is roughly the same. There are definitely cases where that's not true, but in this domain (serialization) a macro based solution is well understood. See https://github.com/devinus/poison/blob/62e98f19552289f3f7139... for a macro based example in Elixir.
I believe, but am not sure, that this is possible for Go. (Of course, whether this is a good idea is another thing entirely. I probably wouldn't have included macros if I had been put in charge of Go 1.0, given Go's goals of simplicity.)
More on this from my former colleague Dave Herman, who did his dissertation on macros: http://calculist.org/blog/2012/04/17/homoiconicity-isnt-the-...
I did some testing with gojay and it did work as a drop in replacement for most of my usage. However the performance improvements I saw in my benchmarks were not nearly as favourable as those published in the projects git repository. I'm sure I could get better results if I played around with their APIs a little more rather than just using the mashallers but frankly the utility I'm using it in favours the flexibility of encoding/json a little more anyway, even if that does cost me a little in performance (and to be clear, it really wasn't much as I needed to iterate the execution of my utility a thousand times just to get any meaningful differences between the two libraries. So we're not talking real world usages).
That said, if you're building high performance servers then I'm sure gojay would really stand out. On reflection (no pun intended), my requirements wasn't really the target use case for this package.
The rest should be abundantly clear which use case would apply to anyone who's spent more than five minutes in Go (or any programming language that supports reflection) and had read the first like of the packages readme (ie that it doesn't use reflection).
It's definitely worth remembering that one doesn't have to use structs and tags to write nor read JSON in Go before people start bitching about boiler plate code and lack of macros.
An additional reason for codegening is the extreme syntactic simplicity of the language: there is little syntactic sugar and it has a tiny, simple, explicit specification.
On the other hand the syntax is also meant to be clear, unambiguous, and human-readable. I was thinking what is good for humans to read might not be the easiest to get programs to output.
Question: since you seem to know about Codegening, do you find Go's grammar, syntax, etc to be a good target for codegening?
I don't have a more specific question but you could talk about any other feelings you have about codegening against Go (or any other language)
One very nice feature of go is that the formatter is available as a library (https://golang.org/pkg/go/format/#Source), so you can gen "raw" code and then throw it through the formatter to get nice pretty output.
I'm not sure how most languages tackle high performance json encoding/decoding, but I have seen a few .Net implementations that take advantage of the JIT to gain performance while providing a more seamless library consumer experience.