Guiding Principles
When we're making decisions about the language, we've got some core principles that guide us. Think of these as the vibes we're trying to maintain. They're not rigid rules — sometimes they even conflict with each other — but they help us make consistent choices about what belongs in the language and what doesn't.
The Principles
1. Existing code is important, existing implementations are not.
We care deeply about not breaking your programs. But we're not gonna perpetuate bugs or quirks from specific compilers just because "that's how Implementation X does it." Your code matters; their bugs don't.
Example: Say Compiler A has a bug where it incorrectly evaluates certain edge cases in integer overflow. But millions of programs are written assuming the correct behavior. We're gonna spec the correct behavior, even if that means Compiler A needs to fix their bug. Your code that does the right thing stays working.
2. Code can be portable.
You should be able to write programs that work across different systems without a ton of modification. We're gonna make that possible and relatively painless.
3. Code can be non-portable.
But hey, sometimes you need to get hardware-specific and squeeze out every drop of performance or access special features. That's cool too. We won't stop you from doing what needs to be done.
4. Avoid "quiet changes."
If we change something, your code should either keep working or give you a clear error. We really don't want situations where valid code silently starts doing something different. That's just asking for bugs.
Example: Imagine in version 1.0, the expression x / y rounds toward zero. If in version 2.0 we decided to round down instead, that's a quiet change — existing code compiles fine but suddenly produces different results. Super dangerous! Instead, if we really needed to change division behavior, we'd introduce a new operator or function so the old code either keeps working or fails to compile, forcing you to update it consciously.
5. A standard is a treaty between implementor and programmer.
This spec defines what both sides promise each other. Implementors promise certain behaviors; programmers promise to write code within certain boundaries. Everyone knows what to expect.
6. Keep the spirit of the language.
Every language has a personality, a core philosophy. We're gonna respect that and make sure new features fit the vibe rather than bolting on random stuff that feels out of place.
7. Support international programming.
The world's a big place, and people code in different languages (the human kind). We should make the language work well for programmers everywhere, with different character sets and locales.
Example: String literals should handle Unicode properly. Variable names shouldn't be restricted to ASCII — if you want to name your function 计算 or вычислить, go for it. Date/time handling should understand different locales. Error messages should be localizable. These things matter when you're building software that works globally.
8. Codify existing practice to address evident deficiencies.
If something's working well in the real world, let's make it official. But if there's a known problem with how people do things, let's fix it while we're at it.
9. Minimize incompatibilities with previous versions.
We don't want to break your existing code unless there's a really good reason. Stability matters. Migration headaches are not fun for anyone.
10. Minimize incompatibilities with related languages.
If there are languages in our family tree or close neighbors, let's try to stay compatible where it makes sense. Reduces cognitive load when switching between languages.
11. Maintain conceptual simplicity.
Keep it simple, friend. Complexity should only show up when it's genuinely necessary. A language that's easy to understand is a language people will actually want to use.
How This Works in Practice
Here's the thing: these principles sometimes pull in different directions. Portability vs. performance. Simplicity vs. features. Compatibility vs. fixing old mistakes. None of these principles is absolute.
When we're evaluating a proposal, the more it violates these principles, the stronger the justification needs to be. Most of our decisions end up being a careful balance between competing concerns. That's just how it goes.
A Real Example: Adding Array Bounds Checking
Let's walk through how these principles interact with a concrete decision. Say we're considering whether to add mandatory compile-time array bounds checking.
Principles in favor:
- Principle 8 (Codify existing practice): Tons of bugs come from buffer overflows. Modern languages check bounds, and it's proven valuable.
- Implicit safety: While not explicitly a principle, having fewer buffer overruns would help users.
Principles against:
- Principle 3 (Code can be non-portable): Sometimes you want to access memory beyond array bounds (like in custom allocators). Mandatory checking would prevent this.
- Principle 6 (Keep the spirit): The language's spirit includes "trust the programmer" and "no hidden costs." Bounds checks have runtime cost.
- Principle 9 (Minimize incompatibilities): Existing code that does intentional out-of-bounds access (unsafe, but sometimes necessary) would break.
- Principle 11 (Maintain simplicity): Adding mandatory checks increases language complexity.
The resolution: Make bounds checking available and encouraged, but not mandatory. Provide compiler flags to enable it, make it the default in debug builds, and allow programmers to opt into it in production. But don't make it impossible to disable for the rare cases where you know what you're doing and need that control.
This satisfies most principles: existing code keeps working (9), programmers can choose based on their needs (3, 6), safety is available for those who want it (8), and we keep the language simple by not adding complex rules (11).
See how that works? No single principle won. We found a solution that respects the balance of our principles. That's what good language design looks like — finding the sweet spot where multiple concerns can coexist.
Common Misconceptions
A few things to clear up about these principles:
They're not ranked. Principle 1 isn't more important than Principle 11. They all carry weight, and we consider all of them when making decisions. The ordering is just for organization, not priority.
They're guidelines, not laws. These aren't hard rules that we mechanically apply. They're more like the North Star — they help us navigate, but we still have to chart the course based on the specific situation. Sometimes the right decision involves bending a principle if the overall outcome is better.
They can conflict, and that's okay. When principles pull in different directions, it means we need to think harder about the decision, not that the principles are broken. The tension between them actually helps us find better solutions than we'd get from following any single principle dogmatically.
They evolve with experience. As we learn more about what works and what doesn't, these principles might be refined. They're based on decades of collective experience, but they're not set in stone forever. We're practical, not dogmatic.