Dynamically typed systems effectively come with meta-programming capabilities for free, but are dynamic systems fundamentally better at meta-programming?
This led me to a hard question: are dynamic systems fundamentally better at meta-programming?
Well, the static languages I know rely on reflection for meta-programming. Unfortunately, reflection is often slow and arcane.
Some thought experiments
- Do static languages fundamentally need to rely on reflection to enumerate type members?
- No, the information is present at compile-time and a consistent method for enumerating members could be generated.
- not at runtime, that would be dynamic typing
- Can the types be generated at compile time?
- This is a hard question that is well explored in this article. In short, yes. Our program can’t operate on something that is entirely unknown. Static languages force us to make our assumptions explicit. Even if they are very loose expectations. Dynamic languages often let us leave assumptions of structure and type implicit, but still necessary for the code to execute. Since we encode these assumptions when we write the code, the information is present at write-time.
This leads me to conclude that static languages can theoretically meta-program as well dynamic languages. It is a limitation in the tooling that prevents our code from utilizing itself as information to generate code at compile-time.
Think of examples like proxying, cloning, and mapping. We programmers can see the relationships and generic process for implementing them, but the language isn’t smart enough to harness it.
Dream Come True
While pondering this I came across C# 9 Source Generators. They fill this expression gap by working like compile-time reflection. We can create code using our code as data! It is not limited to our own code though, we can generate code based on any data at compile-time!
In summary, dynamic languages are not fundamentally better at meta-programming than static ones and C# 9 will be closing the practical gap with Source Generators.