Differences From Rust

Ki is very Rust-like, but not entirely on purpose. Many of Rust's solutions to problems are largely derived from other languages (smart pointers from C++, option types from OCaml), and Ki takes that very same approach. Ki uses a lot of Rust's ideas: traits, smart pointers, strong types, syntax, mutability, references, and I wholeheartedly admit referring to Rust's design and API docs frequently during the design phase.

Ki's mission is also slightly different from Rust's. Rust aims to be a systems programming language, one that can implement both a kernel and a front-end GUI. It accomplishes this via the unsafe block, which is a pretty good compromise, especially given its goals of "safety, speed, and concurrency".

Ki is unreasonably uncompromising when it comes to safety, likely to the detriment of its user count. Compile-time bounds checking, explicit overflow handling, mandatory initialization, mandatory checked indexing, and mandatory NULL handling in the FFI are all onerous requirements which, in Jonathan Blow's words, lower code morale. Ki's lack of an unsafe block, and thus its inability to write to raw, unallocated memory means it cannot be used to implement kernels and device drivers.

But we also think that Ki's design should raise code morale higher than its strict safety requirements lower it. It is a parsimonious language with few concepts and few keywords. Its design is generally consistent and ergonomic, and includes high-level concepts like first-class types and functions, built-in concurrency primitives (like channels), syntactic sugar for range checking and collection building, and so on. For as much as Rust can (and should) replace C/C++ for writing low-level and speed-critical code, we feel that Ki's extended emphasis on safety make it a better choice to replace C/C++ for writing application-level software that can tolerate running within 90% of C/C++ speed (at the worst).

For people who like lists:


  • Variant types
  • Runtime type validation
  • Mandatory explicit overflow checking
  • Mandatory initialization
  • Mandatory checked indexing
  • Mandatory checked NULL handling in the FFI
  • No initializers or destructors
  • No unsafe block
  • No lifetimes
  • No raw pointers
  • Generators
  • Range-limited integer types
  • Slower (ever so slightly!)


  • Faster
  • Raw pointers
  • unsafe block
  • Explicit lifetimes