I've blogged before about my plans to create a programming language of my own. I have a long list of features I'd like to experiment with. I want to incorporate features that are not commonly found in other languages. For instance, the language is going to have an extensible grammar. I'd like to have program images that can be suspended and resumed like in Smalltalk. I'm also trying to sketch out a JIT compiler that compiles itself. Unfortunately, so far, I've spent more time thinking about the design and implementation of this language than writing any code. I wrote a decent amount of code, then ended up scrapping it and starting over, only to think that I should maybe start over again.
Part of the problem, I think, is that I keep wanting to plan 20 steps ahead. My language, zeta, is going to have a few features which are fairly uncommon/experimental, such as the extensible grammar. I don't know ahead of time precisely how these features are going to work out as part of the overall design, there are many small micro-decisions to make, things that could be implemented this way or that way, and that's where I keep getting stuck. I keep worrying about issues such as performance, garbage collection, multithreading, and how different language features will integrate with one another. Inevitably, I end up having to admit that there are simply a lot of important questions I don't yet have an answer to. Language design is hard, and so is compiler design.
I think that this is a common problem with ambitious engineering projects. When you're trying to innovate (or just do things differently) on ten different fronts at the same time, there are simply too many unknowns, too many degrees of freedom. This is why innovation is typically more incremental than revolutionary. People build on trusted foundations, and maybe they add one or two cool new features on top. When you try to reinvent everything, there are just too many problems to be solved at once. Solving multiple problems simultaneously is problematic, because it gets in the way of building your product. You want to create something that's globally optimal, as good as you can make it, but you keep having to make technical decisions which you simply don't have enough information to make. Each of these decision points stalls you a little bit, because making the optimal technical decision requires taking the time to pause and gather more data. Worse yet, not all of these technical decisions are independent, some are simply incompatible with one another. Choices you make now will push you down a certain path later down the road. Sometimes, you make a certain set of choices, and later on you realize that you went down the wrong path, and you have to backtrack.
I keep wanting to do the ambitious thing, and getting into complex, elaborate designs as a result. I start building, and I often end up backtracking. I've decided to take a step back and ask myself some important questions, such as, why "Why do I even want to create a programming language?" and "What am I getting out of this?" One of the things I've come to realize is that creating a programming language as a hobby project for the simple joy of doing it, and creating a programming language which I hope will eventually become popular and dethrone python are two very different projects with very different requirements. Creating a programming language for fun is a project with very loose requirements and much freedom to explore, motivated by the joy of programming I discovered when I was a teenager (and hope to keep alive for a long time). On the other hand, creating a language in the hope of whacking Python in the gonads with a 2x4 is a project likely motivated by my inflated ego, and my failure to integrate mindfulness meditation into my daily routine.
Designing and implementing a popular programming language means I have to care about many issues such as:
How learnable/palatable the syntax is to the masses
How beginner-friendly the language is
Integration with C/C++ code
Deployment, how easy it is to install my compiler/VM
Being able to generate binary executables
Multi-platform support, including mobile devices
Unicode support and internationalization
The absolute performance of my language
Multithreading and parallel performance
Security of my implementation (exploits)
Responding to the wants and needs of the community
All of these issues, and more, are things that necessarily strongly influence the design of a language. They are things that limit my ability to freely explore language design. Most importantly, creating a language with popularity in mind means that this project starts to be very much about caring about the wants and needs of the community. Lots of limitations on my ability to pick the language design I want, and having to care (work for) a huge community means that the project starts to look a lot like a job
rather than a fun hobby. Hence, if I want to explore language design, maybe I ought to go about this project differently, scale down my ambitions, and go for something less grandiose.
I've decided that I'm probably not ready to build a commercial/popular language. Instead, I'm building a small-scale prototype. I've asked myself "What's the most important language feature I want to experiment with?" The answer is the extensible grammar. What I'm doing, then, is building a sort of Minimum Viable Product (MVP). A tiny minimalist language with just the features I need, so that I can get to the interesting part of experimenting with an extensible grammar as soon as possible. Right now, this language is interpreted only, and it has no garbage collector (it never deallocates). Even this, I'm finding out, is challenging. Even this tiny project involves solving many technical problems, but things are already much simpler, and most importantly, much more fun. Once I have the extensible grammar working well, I'll move on to adding other features, and exploring other equally interesting technical problems.