Please see the disclaimer.
Expect more items to be added in the future.
tl;dr My dream programming language should be easy like a scripting language and fast and raw like low-level languages.
It should be no secret, among people who know me even a little bit, that I like to work on programming languages.
Why? I don’t know. I just do.
But I have been feeling uncomfortable as of late because it seems like all of the good ideas are already taken by programming languages.
However, I began to realize that all of the good ideas have not yet been combined into one language. And I would like to make that language.
With that said, here is a list of the biggest features that I want in a programming language, that I must have in order to feel like I have the best language available:
- First-class functions.
- Reflection and first-class types.
- Compile-time execution.
- Time management.
All new languages nowadays, in my opinion, should be safe. We have enough computing power to handle run-time checks, as much as they are necessary. And we currently have a crisis in cybersecurity. We need to rewrite much of our infrastructure in safe language, i.e., not C and C++.
When I wrote a
bc, I wrote it in C. However, that did not stop me from
taking advantage of concepts from functional programming.
All variables had to be zeroed out before they were used as a result value. This made it necessary for me to call a function to do just that, for every type of math operation.
However, the entry point to each operation was a function that was for each specific operation. That meant that the control flow went something like:
entry_op -> zero_func -> actual_op
I did not want to duplicate
zero_func for every operation, so I took a page
out of functional programming and passed
course, I did it with function pointers, but the idea was there.
First-class functions (including closures) are quite useful for modularity and a whole host of other things. Modern languages cannot do without them.
Reflection and First-Class Types
It took me a long time to even figure out that these things existed, but they do.
Most people know what reflection is, but many may not have heard about first-class types. That just means that you can pass types (type names) into functions, as well as return them. In addition, you can use them as type markers.
This allows a certain amount of dynamic features. And since I want a statically-typed language (more on that later), that would be nice. It also helps modularity.
But the biggest reason will only become apparent after I introduce the next must-have feature.
If I am correct, this is a relatively new thing, at least to imperative languages. Compile-time execution (CTE) is when the language can run code in the compiler.
This one blew my mind the first time I saw it in this video. And though his demo is a little silly (like the one in this video), it does show what is possible with this one feature. It removes the need to an extra build system (like CMake), it allows for easy profiling (like in the second video), and it will allow many other things that I haven’t even thought of.
This feature combined with first-class types makes implementing templates easy; in fact, implementing templates is unnecessary when both of those features are present.
The greatest innovation of Clojure is its approach to identity and state. The creator has a great talk on it.
When I first heard this, I remembered something I was told by a professor of mine: the best programming language will be one that manages time.
I realized that the creator of Clojure and my professor were talking about the same thing: the most important thing that a programming language does is give the programmer tools to manage values that change over time.
If you think about it, it makes complete sense. Those values that do not change (immutable values) do not need to be managed because they can be accessed from any thread without locking. However, mutable values do have to be managed carefully.
Smaller Essential Features
I have a list of smaller essential features:
- Static typing.
- Compiled, but able to write scripts. (This should come for free from compile-time execution because the compiler needs an interpreter anyway.)
- Polymorphism (but not necessarily object-orientation).
- Low-level and high-level data structure forms.
Here are some features that I am not sure are necessary:
- Built-in concurrency, like Erlang or Go.
- Garbage collection (I would prefer to not have GC, like Rust).
- Undefined behavior (enables many optimizations, but safety comes first).
- Correctness proofs (obviously the compiler should be correct, but proofs of that, or that the generated code is correct, may not be necessary).
One Feature to Rule Them All
There is really one feature that I want: my language should not be “low-level” or “high-level.” It should be comfortable to use at all levels of computing, from raw speed currently dominated by C and C++, to the ease of use (and speed of implementation) of scripting and functional languages like Python, Lisp, and Haskell.
Why is this the one feature to rule them all? I will explain in a future post.