2019 just arrived and as in recent years I used my free time to think about what I would love to see or contribute to. Naturally, if you know me, programming languages capture my attention quite easily.
Years ago I started thinking about the ultimate programming language. Call me naive but I still think the idea of such a language seems appealing. I concluded that such a language must be very strong at meta programming, i.e., programming the programming. To show this strength (or confirm it) the language itself must be defined in the language. This concept is similar to writing a compiler for a language in that language.
While writing a compiler for a language in itself is a feature that has been long figured out and fruitful for dogfooding purposes, defining a language in the language is much more complicated. Right now my solution proposal (there are certainly multiple, I'll explain why I favor this one) would be:
- Define the basic building blocks (tokens) of the language
- Define a set of compiler keywords / identifiers
- Define how calling a function looks like
- Expose a compiler API incl. a way of introducing new syntax / grammar
- Use the first three bullet points to define the whole language via the last one
If done correctly we are able to define the language in a primitive version of the language. Notably, such an approach would already define some primitives directly leading to natural abstractions. For instance, it is a possible way to already define a primitive like inserting a marker or a jump declaration targetting it. As a consequence, higher level constructs, such as a loop, could make use of this lower level primitives, which nicely outline the level of abstraction.
Ultimately, this would implicitly allow writing transparent (or zero-cost) abstractions, since these "macros" operate on a language level and are all resolved by the compiler (or language) itself.
The way I imagine this all would work out sanely is that we have multiple layers as shown in the next diagram.
In the center we have the base definition of the language. This should be fixed and needs to be carefully specified to be both, solid and flexible. In the end this only provides the basis for the core language, which will be properly versioned. Great thing about this design is that any version of the language works with any version of the compiler (well, at least if the base part has been done correctly - in practice we will certainly see some dependency here).
In the outer ring we have some extensions to the language that are useful enough to be published in form of packages. Depending on the kind of project that is written one or more of these may be included. The packages (like any other) have to be properly versioned and will specify dependencies.
Now that I've briefly explained my old thoughts (which are still valid today), I would like to describe what I want in a programming language in the year 2019. Consider this a wishlist:
- It must be dynamic first to allow fast prototyping and gain flexibility when wanted.
- It must be (optionally) statically typed. Preference is on using the static typing to give best performance.
- For the static typing a rich (powerful) type system with strong type inference is desired. The system should be (at least partially) algebraic.
- Must have first-class functions that form the essential unit.
- Must have modules that can be bundled to packages.
- I want an elegant package manager that makes working with dependencies a breeze.
- I must be able to do manual memory management even though dynamic ones using, e.g., reference counting, are available as well.
- Should handle asynchronous calls in an efficient manner, potentially in message passing (actor) or async/await manner.
- The language must compile to web assembly (WASM) first.
- Optionally, the language should be able to compile to native code (ARM, x86, ...).
- Favor convention over configuration for projects, such that I don't need a huge boilerplate to start and a single file is already sufficient.
- Must come with a solid (independently of the language or compiler versioned) framework.
- Must include zero-cost abstractions (see earlier point).
I think libraries should be delivered already "compiled" (to WASM), where dependencies are already reduced to used-code (tree shaking optimizations performed) and bundled. This eliminates needs for complicated transitive dependencies. If we really want to dynamically reference dependencies of dependencies, these should be stated as peer dependencies first. As a consequence one author will never be surprised about conflicting transitive dependencies or what kind of "hidden" dependencies are installed / used.
Now you think there is a catch and I am actually now revealing a language that already exists. I'm afraid I cannot give you this pleasure right now. All I can write is that the formerly described points take lessons and ideas from several languages (as usual), which can be boiled down to JavaScript / TypeScript, C# / F#, and Rust.
What is your wishlist for a programming language in 2019? Do you see anything that you would fully agree or disagree to? Let me know on Twitter or via mail!