This is a programming language syntax I sketched out a couple of months ago. My goal was to create a syntax that was useful enough to not be (just) a joke, but weird enough to make people angry.
I started working on this again a few weeks ago, and I've gotten it much farther along than any programming language project I've done before (the screenshot above is code that actually runs.)
Since the previous post, I've changed the language a bit:
🧌 Instead of "clusters", there are just object literals; classes are objects that produce other objects. Each object literal defines a "hidden class", and its instance variables are the values closed over by its methods.
Object literals can contain either key-value pairs (which generate a bunch of methods for working with those fields) or method definitions (with no additional methods), but not both.
🧌 I got rid of the lambda syntax, and now application/pattern matching are done with a method whose name is the empty string. A lambda now looks like:
[{: arg} arg + 1]
And pattern matching now looks like
list{:[
{head: h tail: t} 1 + t{length};
{nil} 0;
]}
🧌 I added var bindings and method parameters. These work a bit like inout parameters in Swift:
let obj := [
{inc: var x}
set x := x + 1
self
]
var x := 1
var y := x
obj{inc: var x}{inc: var x}
# x = 3, y = 1
Only the binding is variable, not the value itself, and methods cannot close over var bindings, they can only accept them as parameters. Consequentially, var allows you to write in a procedural style but does not allow shared mutable state. (There are a few actually mutable types in the language, too, but you shouldn't need to use them too often.)
🧌 I added dynamic scope with provide <name> := value and use <name>. While it's easy for people to go overboard with dynamic scope, I think it's better for the language to support it correctly, rather than encouraging users/framework authors to hack it together via globals & shared mutable state.
Ultimately, I want to use this for something like capability-based security, where the host provides objects that grant access to logging, the file system, the current time etc., and test runners provide mocked versions of those.
I have a few remaining features I would like to add:
👹 Async/await
👹 Error handling: at the very least, I need a way to register resource cleanup handlers when the program crashes.
👹 Control-flow propagating blocks: in languages like Ruby or Smalltalk, control flow is done with blocks -- when you return from inside a block, you return from the method in which it is defined, not the block itself. These flow-preserving blocks should also be able to do anything that code in the parent method can do (e.g. access & update var bindings), but they need to be restricted in some way such that they do not allow shared mutable state or nonlocal jumps.
👹 Pattern matching: I would like method dispatch to be able to do just about everything that pattern matching does in functional languages.