Guiding Principles
No One Best Thing
Every design needs to consider a series of trade-offs. Programming languages are no different. There is no single “best language” for everyone. Even individual developers will want to change languages based on the domain they’re working in at the moment. At some point there is tension between competing values. Python is much more approachable than C, but C is much more performant than Python.
Bryan Cantrill’s talk, Platform as a Reflection of Values, illuminates this tension and provides a useful list of values to consider. So, what’s most important in the design of Shim?
Shim Values
The Shim language has these primary values:
- Debuggability
- Velocity
- Simplicity
- Robustness
Other values are important, but these are the priority. The needs of game scripting are heavily represented here. If you intend to use Shim outside of game programming it may be useful to understand how well your needs align with the values here. Much is incumbent on the host application to realize the values outlined here.
Debuggability
Particularly in the realm of game programming, reproducing and debugging issues can be a frustrating and time-consuming experience. Shim needs to provide the runtime that enables a world-class debugging experience. The entire runtime was built to be deterministic and able to be snapshot. Memory mutations are tracked to enable incremental snapshots and time-travel.
Debugging is at the core of the design of the language runtime, and the language itself was designed with that in mind. This design philosophy is invisible if you just read the documentation, but it’s the key reason why the language was made.
Velocity
When issues can be found easily, they should be able to be fixed easily. Changes should be able to be made with as minimal friction as possible. Getting personal, I want to save a file and immediately see the result in-game. I don’t want to be restricted to just changing method bodies like some hot reloading systems. I want to add new data structures, add members, remove members, change method parameters, and more.
I want Shim to enable a state of flow.
Simplicity
Shim should be simple. Simple means having everything you need and nothing you don’t. It means rejecting complexity even if it increases verbosity. Simplicity is about building things out of smaller pieces. Simplicity means doing what’s expected even at the cost of performance.
Shim does not provide a way to dynamically access members of a struct within the language itself. It would be almost trivial to add, but would greatly complicate ahead-of-time compilation.
Robustness
When releasing a project, you need to have some assurances that the code you wrote is valid. That’s why it’s incredibly important that Shim provides type checking. It’s not more important than the other principles. It’s better that typing is optional (or at least inferred) to keep development quick, but projects need to be able to harden themselves when needed. Especially if people are using LLMs to generate or understand code, types help ensure that everyone is creating valid programs.