| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [View Raw Code] [Original HTTPS Page] |
.. index::
single: design philosophy
This document describes the why behind daslang — the problems it was built to solve, the trade-offs it makes deliberately, and the principles that guide its evolution.
daslang was born out of concrete problems at Gaijin Entertainment. The studio had Lua (via LuaJIT) and their own fork of Squirrel integrated into a large C++ game engine. Both languages hit the same walls:
A prototype interpreter — tree-based rather than bytecode-based — was already outperforming LuaJIT's interpreter by a wide margin, simply because it did not marshal data. "Give it decent syntax and I'll integrate it tomorrow" was the challenge from the engineering side. daslang shipped its first production integration shortly after.
daslang serves three overlapping groups, in order of population size:
Iteration speed is king. A full production game recompiles in ~5 seconds on decent hardware. Hot reload is built in. The entire developer experience revolves around the idea that you should never have to wait.
Explicit, not implicit. daslang does not do work "under the hood". There are no hidden type conversions (not even int to float), no silent allocations, no auto-casting outside of type inference. If the code does not say it, it does not happen. options log prints the full output of the compiler — total transparency about what your code becomes. Macros can add behavior; the base language does not.
99% safe, not 100%. The goal is to eliminate 99% of the bugs seen in real-world C++ code — use-after-free, null dereferences, type mismatches, off-by-one errors — without imposing the full cost of formal verification. This is not Rust-level safety; it is pragmatic safety for game developers who can handle an occasional crash but should never be chasing undefined behavior. Safe code is the default. unsafe blocks exist for the remaining 1% where you need direct memory access.
No data marshaling. daslang's data layout is essentially identical to C++ (minus bitfields). Calling from C++ into daslang or from daslang into C++ does not copy, convert, or box data. This is the single most important performance decision in the language — it is what makes daslang viable as a per-frame ECS scripting language where Lua and C# are not.
If it gets slow, you can fix it. Garbage collection exists but should rarely run per-frame. Manual delete is available to reduce GC pressure when needed. Ahead-of-time compilation (AOT) to C++ is always an option. The philosophy is: the fast path should be fast by default, and when it isn't, the language gives you tools to make it fast — deterministically, not hopefully.
The language should reflect the problem domain. The compile-time macro system (inspired by FORTRAN + LISP, with HAXE-style reification) exists not to keep the language core small, but to let libraries reshape the language to match the problem they solve. Less verbose solutions are better solutions. Pattern matching, LINQ, JSON — all are implemented as macros that extend the language rather than burdening the core.
daslang has three execution tiers, all planned from day one:
The hybrid mode is the practical sweet spot: each function has a semantic hash. When the script changes and the hash still matches, the AOT-compiled version is used. When the hash changes, the interpreter takes over until the next AOT build. This means a December 31st hotfix can ship new script without a full rebuild — if the semantics didn't change, it stays native; if they did, the interpreter covers it at acceptable speed.
daslang is statically typed — stricter than C++. a = 0 means a is an int, full stop. Every expression has a type known at compile time.
Static typing was chosen for two reasons:
Aggressive type inference (auto) is a deliberate "best of both worlds" choice. You get the safety of static typing without the annotation burden of C++. Most intermediate types are irrelevant to the programmer — the compiler infers them, and static_if with typeinfo provides compile-time reflection when you need to branch on types.
daslang has two syntax modes:
Gen2 was created entirely from user feedback. Two distinct groups of programmers prefer different styles. The intent is to eventually transition fully to gen2 (avoiding the maintenance cost of two parsers), but gen1 may persist indefinitely. Gen2 also has a simpler parser, which is a practical advantage.
Even in gen2, some significant whitespace remains — for example, automatic semicolon insertion at end-of-line — so gen1's legacy is not entirely gone.
Since GitHub Copilot emerged, daslang's syntax has been actively shaped by AI code generation. Copilot frequently suggests code that borrows conventions from Python, TypeScript, or C++ — commas instead of semicolons in argument lists, -> instead of : for return types, and so on. Rather than rejecting these suggestions, the parser was made flexible enough to accept them.
For example, both of these are valid daslang:
def foo(a : int; b : float) : bool { return true; }
def foo(a : int, b : float) -> bool { return true; }
The first form uses daslang's native separators (; between arguments, : for return type). The second uses conventions AI models pick up from other languages (, and ->). Both compile to exactly the same thing.
This is a deliberate design choice: if AI writes code that looks right, the language should accept it. The alternative — fighting the AI — wastes the programmer's time, which violates the core principle that iteration speed is king.
daslang was born as an embedded scripting language and that remains its strongest use case. But the language is expanding:
The original name "daScript" caused people to assume it was a scripting language in the traditional sense — interpreted, dynamically typed, slow. It is none of those things. The rename to daslang signals that this is a full programming language: statically typed, AOT-compiled, with JIT and standalone binary support.
As the blog post put it: "It's not a script, so renaming it was a matter of time."
daslang occupies a unique position among game-adjacent languages:
daslang is a pragmatic language built by game developers for game developers. It trades theoretical purity for practical speed — in compilation, in execution, and in the daily workflow of the people who use it. Every design decision traces back to a real problem encountered in production game development at scale.
| Back | FazBrowse Home | New Git URL |