Q>> aka Q Language
Q>>, also known as the Q Language, is a minimal programming language created to write the Q// aka Q Shell in. It’s an experiment at this stage.
Documentation & FAQ
All of Q>> lives in the Q// repository, in the
Rules of Language Design
Counteract Complexity Growth
An element can only be added if its net outcome simplifies the language. Meaning, that the essential complexity introduced by the new element – especially considering its combinatorical impact – must be less than the gains in expressive power. Every new element must be justified and in every case where the benefits don’t clearly outweigh the costs, we shall err on the side of leaving the element out.
Soon enough I had to begin thinking about safety, null pointer checks and the like. And so I felt that the best would be going with the C philosophy: the runtime lean and mean without any checks, the transpiler and the standard library ensuring correctness towards the C API thereby guaranteeing that Q>> code won’t produce runtime errors. Unless, of course, the application messes with the C API of the runtime, in which case it’s “caveat emptor”.
This is the story how the language came to be, one orthogonal decision at a time, building the minimum amount of dimensions in.
Integers, Strings, Identifiers
These were the elements the parser supported initially. No other signs or symbols. So we’ll start the diary from here, arguing for and against any and all new language elements.
I don’t feel like complicating things, building a monstrous parser to deal with deep expressions in parentheses, operator precedences, L- and R-values and the like. So I shall attempt marrying a Forth-style simplicity with a Ruby-style fluidity.
Single Parameter and Results
There won’t be multiple parameters because they complicate things. Also, because they’re kind of an antipattern and are easily misused. Single value in, single value out, and that’s it. And then, because tuples must also be natively supported, you can pack things to your heart’s content.
Streaming All The Things
Then, I also wanted to eliminate the difference between single values and collections, because otherwise streaming is of limited use only and the language isn’t consistent. And then, if it’s single parameter in, then we may as well stream parameters in as opposed to passing arguments. And so that gives us our first program in Q>>
# let's exit with status 123 123 >> exit
And just like that we’ve added the next syntactic element to the language, the
>> pipe operator. As to the contribution vs cost balance of
>>, let’s consider that it’s also part of the name of the language, and not without reason, for it eliminates (embedded) parentheses and whatnot.
Namespaces and Blocks and Stuff
Miscellany and trivia and whatnot.
A Brief History of Q// and Q>>
I began the first version of Q// in Ruby, that was fun, went smoothly, as one would expect, however at one point I decided more languagism would be called for, so I started it again in Elixir (functional, actor based, with pipe operator and more). While Beam (the Erlang runtime) took some getting used to, things worked just fine, except that the 200ms it took to start and run the final product, a command line tool, was not acceptable. Even Ruby came at about 100ms, which, after the Elixir experience also became noticeable, i.e. too much. Hence I moved to Pony, that has a compiler with an exciting type capabilities model and also comes with actor based concurrency. Soon, however, I realised, that fighting the type system to get basic things, like a test harness, done was too much hassle so I took the easy choice back to what I consider to be an improved Ruby, namely Crystal, that adds types, null safety and compilation. Then I copied the binary to a new machine and it promptly refused to start expecting some library installation (another no-go), at which point I decided I had enough of chasing trends and went back to trusty old C. OMG, was that a bliss! A language that does what and just what I tell it to do is a long-forgotten rarity these days. Such powerful, so thrill! However, soon after that, on the morning of January 1, 2020, I decided, it could still be appropriate to move with the times and heeding the advice of several whom I trust, I decided to gave Rust a try. Then I quickly learned what an overcomplex and unwieldy beast that language is and I dumped it unceremoniously. Then I went for simplicity again, this time on to V, but soon realised that the flakiness is not due to it being in development stage but due to lack of discipline. So I evaluated like a bazillion more compiled languages and moved to Zig. Which, despite its relatively friendly surface quickly manifested its complicated underbelly… which is when I gave up. I’ve gone back to C, the last language that makes me feel 100% confident, and… decided to double the fun, run an experiment, try to come up with a tiny language for Q//. And so I decided to call it Q>> aka Q Language (because I intend to try Elixir-like pipe operators and I felt
>> looks just right for that. So the journey begins…
This is a crazy Odyssey, isn’t it? So here again, as TLDR:
- Ruby: no single binary, somewhat slow, boring
- Elixir: neat, though exotic, way too slow to start
- Pony: way too demanding to achieve simple things
- Crystal: almost boring again, deployment problems
- C: the best language in the universe, kind of old
- Rust: overcomplex beast, demanding, not serving
- V: inherent quality issues, not due to development
- Zig: weird build/test system, weak documentation
- Q>> aka Q Language, or an experiment in purity
The Rust Diaries
At one point I began my Rust Diaries only to abandon the language in a few days. Some of the clues will be in the diaries. In short though: I refuse to work in languages that make me think about their leaked abstractions instead of empowering me to solve my problem. I don’t want to fight my tool I want one that fits in my hand. So thanks Rust, but no thanks.