Influences
At the risk of vanity, here are Ki's influences.
Ada
Ki's variant structs are Ada's discriminated records, and ranges come from Ada
too. Python, of course, has ranges but they're not specific types like Ada's
ranges. The loop
keyword is also from Ada.
C
Ki is largely a reaction to C, and because Ki primarily compiles to C its constructs were always conceived in a C context. Many C programmers say they can see the assembly that would be generated by C code, and while that's at least a little suspect these days, we designed Ki while always considering what the underlying C code would look like.
C++
While I fought it, Ki's parameterized types and functions are essentially C++'s templates. Static functions are also from C++, despite being pretty common (Java, Python, etc.). Unique, shared and weak pointers as well as references are from C++, even though they're used to implement Rust's memory model.
JavaScript
var
comes from JavaScript. ===
and !==
are also from JavaScript and
replace is
and is not
from Python.
Go
Go's zero-values are the basis of Ki's default values in structs. Ki's const
declarations were inspired by Go's. And, again while I fought it, Ki
eventually adopted Go's "name type" ordering for struct fields, functions, and
variable bindings, which is reversed from C. Ki's types are similar to Go's
types as well.
Lua
Ki's component
was inspired by experience working with Lua. Ki's
primitive/type/component datatype system is designed to associate functions
with data, which is "composition over inheritance", or really "functionality
instead of taxonomy". Most languages that take this approach use "interfaces"
(Go, Java) or "traits" (Rust); Ki calls these "components".
I settled on components over inheritance after implementing a widget system in
Lua using a traits library. While it was lightweight and refreshing to think
in terms of functionality instead of category or hierarchy, I was frequently
frustrated that my traits required fields that my underlying data structures
were missing. Thus :requirements
in components was born.
Ki's mod
comes from explicitly exporting tables as modules in Lua.
Python
The for
-in
loop comes from Python. Python's list of special methods
(__iter__
, __contains__
and so on) was extraordinarily helpful. Ki's
generators and list comprehensions come from Python, as does self
.
Python's properties inspired get
, set
, and pred
; I wanted these badly
when working with Lua. I'm somewhat sympathetic to the argument that field
accesses are cheap, so field accesses that aren't cheap shouldn't look like
field accesses, but the alternatives are either a mishmash of convenient field
accesses and inconvenient get_*
and set_*
everywhere, or
Projects tend to bend towards getters and setters anyway, and with this reality
in mind, Ki's get
, set
, and pred
allow for convenience, flexibility, and
consistency, at the cost of some potential surprise, which can easily be
avoided with basic documentation.
Rust
Ki's memory model is essentially Rust's. There are some slight differences but for the most part, Rust did the (astonishing) legwork here.