- < 1k Lines of Code
- Native compilation of code
- Embed Anywhere
What do we keep?
So the first question to as is "what do we keep"? The answer to that is probably the simplest part of it all:
- Object - a collection of named slots
- Number - a variable representation number object
- String - an immutable ordered collection of bytes object
- Array - a mutable ordered collection of objects
- Function - a mapping from an argument object to a return object
What do we get rid of?
- arguments object - it is a hack that should be solved in a more elegant manner
- var declarations - variable declarations are necessary because the scoping rules are broken
- void functions - a function which does not return a value is an optimization technique disguised as a language feature
- prototype property - single inheritance is a bad idea in a prototype based language, Self did it better, so can we
- try catch - exception handling is a product of poorly designed flow control operations, there are better ways
- if else, do while, for, switch case - like try catch, these concepts need to be put to rest, Smalltalk has a better model
- this - we can take a page from Self and use an implicit receiver
Where do we go from here?
So what would a high level architecture look like for the new language:
- 2 Stacks: Object Stack & Partial Continuations Stack
- Everything is a Function
- All variables are properties of Functions
- All non-alphanumeric tokens are operators
- All function calls are message sends
2 Stacks No Waiting
The idea of a dual stack architecture is not all that odd. Forth makes extensive use of the concept to allow for direct manipulation of the flow of a program. By adding or removing partial continuations from the Forth return stack, the programmer can have direct control over how the program will execute in the future. This concept also allows for incredibly powerful programming techniques which allows the user to produce their own flow control structures.
The main concept here involves giving the programmer more control over the future execution state of a program. To that end, we'll designate a few new special operators:
- a -> b // If A Then B is the current continuation
- a ; b // A Then B, B is the current continuation of expression A
- ^ a // Call the current continuation with the result of A
Everything's a Function
- Bit 0 -> 0 | 1
- Byte 0 ... 7 -> 0|1
- Short 0 ... 15 -> 0|1
- Integer 0 ... 31 -> 0|1
- Long 0 ... 63 -> 0|1
- String Integer -> Byte
- Array Integer-> Object
- Object String -> Object
- Function Object -> Object
Variables are Properties too
The primary advantage of this approach is that it conforms well with the concept of an implicit recipient, and also allows for a more legible designation of what is local and what is not. And rather than write this.foo you can save 4 characters and simply write .foo instead. This also has advantages when nesting functions, and allows modules to define "globals" within their own scope, by making them "local" to the top level of the module. This prevents the old global variable scheme from stomping on your local variables due to cross contamination between code bases.
Punctuation as Operators
- ; - continuation operator
- : - slot operator
- , - adjoin/concat operator
- \\ - new xor operator
- @ - address of operator
- ^ - current continuation
- # - number value of object
- $ - string value of string
- bit , bit -> byte
- byte , byte -> string
- int , int -> int array
- string , string -> string
- @string, @string -> string array
- object , object -> object
- @object, @object -> object array
- array , array -> array
- @array,@array -> array array
The new @ address of operator, allows for the construction of compositions of composite objects. When combined with the comma , operator concatenation takes on a distinct flair from addition. When and are used, the comma , operator treats them as if they were designating @ and @ such that , , is an array of 3 empty objects. @'hello', 'world' is an array of strings, whereas 'hello ' , 'world' is a composition of strings into 'hello world'.
Function Calls are Message Sends
The expression f(x) really sends a message f with object x up the Object Stack, until some object has a property f that can be evaluated for x. This concept is vital for building the next generation of networked software, as a script may operate in a scope that includes other computers. There is no good reason that an containing scope need be on the same CPU, or even on the same continent. As such, the message can be passed to any object within the scope. A backend process may be simply represented by an object whose scope our application runs. The removes entirely the need for AJAXianisms. It also makes Erlang look like a backwards bumpkin.
This concept of message send also means that many of the traditional flow control constructs are better modeled by sending different messages. When combined with the functional nature of all objects, decisions are better modeled through a combination of calculation and message sending,than they are special form conditional logic. This becomes doubly important when the scope of previous and future execution may occur on physically distinct hardware and systems.