5 ms·
> The simple approach is to simply add a children() method to the interface and implement it in every kind of node. Very tedious, and boilerplaty as hell. The
by btown 9y ago
> The simple approach is to simply add a children() method to the interface and implement it in every kind of node. Very tedious, and boilerplaty as hell.
The best approach without boilerplate would be to generate this at compile time, not runtime. You could use an approach like in http://hannesdorfmann.com/annotation-processing/annotationprocessing101 http://hannesdorfmann.com/annotation-processing/annotationpr... to create at compile-time, using reflection, a ChildWalker class that accesses the relevant properties for every class annotated with @Node. At runtime, the JIT should get this down to a vtable lookup and field lookups - just about as optimized as you can get.
EDIT: Always remember https://xkcd.com/1205/ https://xkcd.com/1205/ - if it would take 5 seconds to write each children() method, and you write no more than 5 Node classes per day (amortized), then you shouldn't spend more 12 hours writing the code for this blog post ;) Unless, of course, that was the point all along!
- specialist 9y agoDeveloping, debugging, using an annotation processor is opposite of productive. Not recommended.
- wzsddtc 9y agoIt really depends on the annotation processor and what kind of code you are trying to generate. In the author's case it shouldn't take that long nor would it be hard to develop and debug.
- flukus 9y agoI think it depends more on your IDE playing ball with the code generator and custom build steps. Most do an awful job. I'd love one that I could just point to a build tool/script instead of creating it's own.
- quickthrower2 9y agoAlso I've worked places with this magic and no induction or documentation or time for anyone to explain anything. The more behind the scenes hard to discover stuff you implement the better the docs and onboarding needs to be. It can't just be done to fulfill a architect astronaut fantasy.
- flukus 9y agoI don't care so much about the documentation, as long as it's part of the build script (it's own documentation) and not checked into source control. By not checking it into source control it won't be edited, there won't be a mix of generated and custom code. By being part of the build process you avoid the generation tool and scripts being lost to the sands of time.
- quickthrower2 9y agoI like the build process to be committed personally for build reproducibility. It can be in a seperate more secured repository though.
- cel1ne 9y agoI wrote an annotation processor for [0]. If you use Kotlin instead of Java it's way better because no nullability-issues and it's super-useful standard-library. And once you've figured out how to hook it into gradle, IDEA etc., which admittedly cost me an hour or so, you can reuse that knowledge for every annotation-processor to come. I made it a habit to set myself a time-limit EVERY time I start touching the build-process. After the limit has passed it must be faster, more automated, or in any other way more useful, or I will revert the changes. [0] https://medium.com/@spitzwegerich/generated-json-serialisation-for-kotlin-4470dabe40b8 https://medium.com/@spitzwegerich/generated-json-serialisati...
- Cieplak 9y agoAlthough not a realistic option for everyone, I find c++ templates to be simpler than java annotation processors for type-safe compile-time code gen.
- munificent 9y agoOr, heck, just hack together a little script to generate the code and hook it into your build system. You don't need anything as fancy as an annotation processor. A handful of Python code could accomplish just as well.
- cel1ne 9y agoBut how do you access the original AST in your python?
- munificent 9y agoThere is no original AST. The Python outputs the AST classes, so it is the source of truth.
- cel1ne 9y agoI'm reading Annotations on Java-Code and generating classes from them, so I need to parse Java first.
- needusername 9y agoAn annotation processor does not seem to be a good fit here. Annotation processors can only generate new classes, not modify existing ones. So you would have to make all classes abstract and then generate non-abstract ones that have a #children() method and refer to the generated classes everywhere in your code.
- norswap 9y agoThere are ways if you're not too worried about using private compiler APIs: http://scg.unibe.ch/archive/projects/Erni08b.pdf http://scg.unibe.ch/archive/projects/Erni08b.pdf
- needusername 9y agoI'm really not a fan of these "clever" hacks that rely on compiler internals. That doesn't even work on ecj.
- divs1210 9y agoSeeing all these comments about code generation at compile time makes me wonder if there's an overlap between people who use/write these kind of tools for complex languages and those who post 'what's so great about (lisp) macros?'. eg: JSX users.
- norswap 9y agoIndeed, code generation was going to be my permanent solution, until this turned out fast enough not to bother! Seems like I'm doing fine by xkcd, at least if you remove the time to make a simpler version for the blog post =) And the learning has some value too anyhow.