Decisions
qdx is unusual in what it refuses to do. Each refusal has a reason, and most of the reasons come from what the engine needs.
Nothing is changed after it is made
The engine must give the same result every time for the same inputs, and must be able to keep an old state while computing a new one. Both are simple when values cannot change, and hard when they can. The price is that anything repeated is written as a function that calls itself.
The raw_ functions are the one exception, and they exist so that the library and the engine can be written in qdx and not in another language.
No loops
A loop is only useful with something that changes. Given the rule above, a loop would have nothing to do. A function calling itself in last position costs the same as a loop, and the compiler guarantees that.
One form for each construct
The language is meant to be written by programs as well as by people. A writer that has never seen qdx before does better when there is exactly one accepted form and the error for any other says what was wanted. That is why fields are always named and in order, cases always have parentheses, and lists never end with a comma.
Every match is complete
A match that could skip a case would let a new case be added without anyone revisiting the code that handles the union. Requiring every case turns that into a list of compile errors.
No comments
A comment can drift away from the code it describes, and nothing checks it. Names are checked: a function that is renamed must be renamed everywhere. The language leaves comments out and leans on names, including small functions whose only job is to name a number.
No automatic conversions
Mixing a number with text or a truth value is almost always a mistake. Each conversion is a function call, so it appears in the source where it happens.
One set of top-level names
There are no modules yet. With one shared set of names, a name means the same thing everywhere in a program, and the compiler needs no rules for finding or hiding things. The cost is longer names, and it will be worth revisiting as programs grow.
Everything is built here
The compiler writes machine code and the executable format itself, the library talks to the kernel itself, and the build is a qdx program. Nothing outside the repository can change how a program behaves, and the whole of it can be read in one place.
What these decisions cost
- Code is longer than it would be with loops, generics and function values. A list type and its functions are written out for each item type.
- Building long text or long lists the obvious way can be slow.
- There is no way to hide a helper function.
- Memory is not reclaimed during a run, outside the engine’s own stores.
Each of these is known and accepted for now. None is meant to be permanent.