4 ms·
The author promotes code generation as a practical solution to some problems — but doesn't mention the huge drawbacks for generics, which is why it's generally
by atombender 8y ago
The author promotes code generation as a practical solution to some problems — but doesn't mention the huge drawbacks for generics, which is why it's generally not used.
The reason is that while you can generate a specific implementation when you need it, all the client code will still be using non-generic code. You can't write a function that takes a Set(T) as argument, returns Set(T) as a return value, or receives a Set(T) from a called function — unless you make that part of your code generation pipeline. So the code generation becomes viral, infecting each piece of code that wants to be generic. The entire language needs to be transpiled.
You could lower the barrier considerably by supporting some kind of pluggable preprocessing ("//go:preprocess my_generics_syntax_plugin"), but you'd still run into the problem with combining packages from multiple sources that all wanted to share the same generic types. They would all have to be transpiled the same way.
- hinkley 8y agoI spent a bit of time thinking about this when I was younger, and got as far as thinking about the compiler or runtime relying on some sort of code reuse to improve the space complexity of generics. Each use would have to have its own metadata but should be able to share many function bodies. It won’t work for primitives but I find myself using arrays of primitives less and less.
- mikeash 8y agoSwift does this. A generic function compiled to a single actual function, which accepts metadata about the types passed in which allow it to do the things it needs. The optimizer may, of it decides it’s worthwhile, generate specialized versions of the function, but it’s never necessary.
- jasonwatkinspdx 8y agoI'm guessing the final golang solution will be like this, but with both runtime/boxed and static/typeswitch implementations generated by default, and some heuristic specializations between composing them.
- rocqua 8y agoHere it depends on how you want to use generics. For map<T1, T2> this isn't much of an issue, since whenever you use it you'll probably be using a concrete instantiation. Your point still stnds though, which is why proper generics aren't something you 'tack on' to a language. You have to be prepared for it to be used pervasively. This is probably why templates are deep in the C++ StdLib; as an attempt to ensure templates really are 'part of the language'. Sadly, in this case it really expanded the language. Having a lot of code go through generics isn't necessarily an issue. The potential issue comes from having a lot of different concrete instantiations of your abstract code. That issue might be solveable by smarter compilers.
- jasonwatkinspdx 8y agoWithin go this is not an issue, because go dependencies are source based. Outside of go, assuming compiling a c compat lib, is more tricky, but I don't immediately see why go generics can't reduce to the intuitive pattern you'd get from selective/sparse template instantiation in your dependency before it's included.
- atombender 8y agoThey're source-based, but that still requires that the caller (calling into a package that's using generated code for generics) use the exact same transpiration tech to generate its own code; if it doesn't, it can only interface with the concrete instances of the generic types (e.g. Set_int or whatever).
- coldtea 8y ago>o the code generation becomes viral, infecting each piece of code that wants to be generic. Isn't that the whole idea?
- atombender 8y agoGenerics spreading throughout your app is not a problem, it's that a specialized code-generation solution would work this way. Both apps and libraries would need the same level of support, and at the end of the day you've invented a new language that happens to transpile to Go, on which you'll want to build everything. (In fact, such a language has already been created [1].) It's the awkwardness of the split between ordinary code and transpilation that causes the issues, and the resulting interop issues and fragmentation/competition between flavours. [1] https://github.com/albrow/fo https://github.com/albrow/fo