Skip to content

Features Real and Planned

Jon Purdy edited this page Sep 19, 2016 · 1 revision

This is an index of features that the ideal Kitten would have. The actual implementation is a slowly improving approximation of these features, in our non-ideal world, by a very non-ideal implementor.

Concatenative Programming

Kitten has concatenative semantics: every term denotes a function, and juxtaposition denotes left-to-right function composition. It’s stack-based to make implementing these semantics easier. The intent of choosing a compositional semantics is to make it easy to implement good tools for program visualisation and editing.

Kitten does not have concatenative syntax: each token or word doesn’t necessarily denote a function. It’s probably possible to make a purely concatenative implementation of Kitten, but I chose to avoid it, mainly to match the ergonomics of other languages—when and where whitespace is allowed or can be omitted, the discourse level of error messages, and so on.

Static Typing of Effects and Coeffects

Every term in Kitten has a statically ascribed type, and type inconsistencies are reported as errors. Because every term denotes a function, the type of every term is a function type. Function types describe two things:

  • The effects a term can have on the stack (consumption and production)
  • The coeffects a term needs in order to run (permissions)

That is, the function type constructor has the kind Stack -> Stack -> Permission -> *.

The built-in permissions are IO, Fail, and Unsafe. IO is the permission to break referential transparency: if you call a function multiple times, and it requires IO, then the function may return different results each time. Fail is the permission to abort the program due to assertion failure. Unsafe is the permission to break memory safety, e.g., using unchecked memory accesses.

Example

define lock (-> +IO) { ... }
define unlock (-> +IO) { ...}

permission Locked<R..., S...> (R..., (R... -> S... +Locked +IO) -> S... +IO) {
  -> body;
  lock
  body with (+Locked)
  unlock
}

Here, we define a permission Locked, which declares a permission type +Locked, and defines a function Locked with the supplied type. This function runs a +Locked function by first taking a lock, then executing the function with the permission granted, releasing the lock, and finally returning the results. Permissions can be explicitly and unsafely granted using the with (+Permission) notation; they can be safely revoked using with (-Permission). So a function that can fail can evaluate a function that cannot fail by revoking the permission:

define foo ((-> +IO) -> +IO +Fail) {
  -> f;
  if (some condition) {
    "wah!" fail
  } else {
    f with (-Fail)
  }
}

Native Interoperation with C and C++

A Kitten compiler should implement native bindings to whatever foreign platform it targets. For this Kitten implementation, that means C and, to a lesser extent, C++. It’s possible to simply import a C header and get access to all its functions and types.

foreign c "stdio.h"

do ("hello world" marshal) -> string:
  string puts

Kitten datatypes are interoperable by default with C structures and tagged unions. And Kitten uses the platform C++ mangling convention for names. This allows C++ and Kitten code to access each other’s namespaces and generic functions, and allows for better interop with existing tools geared toward C and C++, such as GDB.