Almost finished exams, and...

I'm almost finished exams (for this semester, one to go) and I have been mulling over the idea of making my own programming language. I've always liked this idea; however, I have never been able to do it, nor did I know any languages that would have made the task of interpreting it fast.

I took one computer science course this semester; I got a decent overview and some useful experience working with C. Believe it or not, I actually like C! Unfortunately, I do everything by the command line and don't have any cool debugger for it so when bus errors or segmentation faults happen they are a pain in the ass to find. Oh well. On to what I really want to talk about: the idea behind the language I currently want to make.

First, it is not object-oriented. It is a lot like javascript in terms of javascript's functional nature, but then it still has a bunch of procedural language constructs built in. Second, you can make object-like entities in it, and I will show how. Third, the core concept in the language is procedures; encapsulated code that is run every time it is called on. A function is simply a procedure with arguments. Here is a steady build up of the syntax. You will notice little things that I've taken from the languages I love.

a = 10 // simple variable definition
a => 10 // simple procedure definition

add_two(x) => x+2 // simple function definition

// more complex function
factorial(x) => do:
    if x > 1:
        return x * factorial(x-1)
    ;
    return 1
;

Okay, so what is the point of the "=>" symbol? That symbol signifies a implicitly returning procedure. Any code in a procedure is executed every time it is called on. If we had a variable that was a procedure to a function call then every time you use the variable that function would be called. Contrast this with having a variable equal a function call; every time you use that variable you will be using the result of the original function call. This distinction is amazingly important and lets one transparently do some really cool things.

Knowing that the procedure is an implicit return, the factorial function above makes sense. The implicit return is a bit disingenuous, it might be better put that a procedure can only have one expression in it. An expression could be doing some math, which has a return value (and so it implicitly returns) or it could be a language construct such as "do" which allows us to encapsulate further expressions. Here are four ways to write the same function:

// Syntax for quickly typed simple functions and more involved functions by
// returning a language construct 
add_two(x) => x+2  // simple named function, implicit return


// Named function that uses the "do" language construct to allow for more 
// expressions/statements.
add_two(x) => do:
    x = x+2
    return x
;


// example of lambda (anonymous/unnamed) functions
add_two = (x) => x+2


// example of a lambda within a procedure
add_two => (x) => x+2

Okay, so I am making slow progress showing why the procedure approach is so cool. The last example of the add_two function above hints at it though. When add_two is a procedure to a function then every time add_two is used it will return a function. When using functions only by their name, we are using the function directly. So, in one hand we have something that returns a function, and in the other, something that is a function. How could this be useful? Well, lets say that we wanted to make an object system. My current plans for this language don't plan for that (even though I recognize its benefits) so the most we can do is approximate one. Associative arrays (or dictionaries in Python) will be how we approach this. We know that every time we instantiate a class into an object it needs to have its own state. I will start with a simple Object function.

/* Object from dictionary. Do not confuse this with real objects in OO languages! */
Object(d:dict={}) => do:
    this = d
    
    if !("construct" in this):
        this["construct"] = () => null
    ;
    
    return (...) => do:
        apply(this["construct"], args, kargs)
        return this
    ;
;

What can be said about the above function? It accepts a dictionary, if that dictionary doesn't have a "construct" key in it then it will create one pointing to an anonymous function. Finally, a function will be returned that accepts any number of arguments, and when that function is called those arguments will be applied to the "construct" function. The idea of "this" is faked by making the "this" variable equal to the dictionary that we are passing off as an object. Here is how we would use this function...

SomeClass = Object({
     /* ... */
});

Unfortunately, there is a very subtle problem with SubClass and it is because of the nature of the scoping rules in Object. Every time SomeClass is "instantiated" it will return the same dictionary! More meaningfully, every instance of SomeClass will act on the same dictionary, meaning SomeClass is a singleton of sorts. This is clearly a big problem: instances of classes should have their own state but also have the same state structure as other instances of the same class. Here is where the power of procedures comes in.

Class(d) => (...) => apply(Object(d), args, kargs)
Singleton = Object

// How to use:

Stateful = Class({
    /* ... */
})

Registry = Singleton({
    /* ... */
})

// note: assuming the syntax allows it, the following should also work:
Class(d) => => Object(d)

There you have it. Using the Object function we now have two simple object types: classes and singletons! The singleton works because all uses of Singleton act on the same result of calling the Object function. The class works because it curries the Object function. Every time Class is called it acts as if Object was called directly: it accepts the same arguments and returns a function that accepts any number of arguments (the constructor). The key is that Object is called only when this mock constructor is called. At that point, a singleton class is built, instantiated, and returned all at once. Pretty amazing!

There are a few other things that I would like to say about the things I want to have working in this language, but that's just it--this language is still only an idea. This is a project that I am extremely interested in pursuing and hopefully I will be able to get something along the above lines working eventually.

  • Development
  • by Peter Goodman on Dec 13, 2007 @ 1:07pm

Add a Comment