Since this is going to be my first post on September, it seems like a good place for a one-sentence introduction of the project. Here it goes. September is an experimental, dynamically-typed, curly-brace programming language with two overarching ideas: extensibility and pragmatism.
The guiding principle: If I can do it, so can you
The idea behind September boils down to one sentence: there should be nothing special about core syntax. If the core language can have a statement like while
, the programmer using the language should be able to create another one just like it, and this should be possible with a reasonably short piece of code in September.
until := ... some magic incantations ...;
The trick is to make those incantations more straightforward than magic, and to ensure that when they’re done, our extensions feel as natural as possible. Ideally, our brand new until
shouldn’t differ from while
at all!
# built into the language
while(itsWeekend()) { party(); };
# added by the user
until(itsWeekend()) { workHard(); };
What’s more, this should not be limited to while
only - if I, the language designer, can create a complex statement like try..catch..finally
, then you as an user should be able to do that too.
The key to extensibility: simplicity
There are existing languages that are said to have achieved the holy grail of extensibility. Lisp is probably the one most frequently used as an example, but others like Forth, Smalltalk, Io or Rebol also have a claim in this space. These languages feel very different, but they have two things in common:
- conceptual simplicity - all the elements making up the program belong to one of only a few types, and many things separated in other languages (e.g. operators and functions) are conflated
- openness to manipulation - replacing or extending things built into the language is possible and straightforward
Having both of those things already gets you pretty close to the extensibility target, but there is a flip side t the simplicity coin: unorthodox syntax and logic. Having operators and functions be the same thing is cool. Having to write 2+(3*4)
because of no operator precedence is a bummer.
All the languages mentioned above have a very unusual feel that is not familiar to the average programmer, and many caveats that you have to be familiar with before you can start being effective. Even the arguably most successful of the three, Lisp, has a lot of problems with readability and a high-learning curve required to leverage its power properly.
The second part of the equation: ease of use
With September, I intend to create an extensible language in disguise. Whenever a choice is to be made between simplicity and ease of use for the programmer, September chooses the latter. If you like, you can forget about the whole extensibility thing and treat as a pretty standard object-oriented dynamically-typed language, just a curly-braced Python if you will:
class Person {
field first_name;
field last_name;
method greet |somebody_else| {
print(format("Hello, {somebody_else}, I'm {first_name}."));
};
method toString {
first_name + " " + last_name;
};
};
But if you’re willing to dwell deeper and discover the inner heart of the language, you will find that class
, field
and method
are plain old functions, not keywords, and that they are actually written in September. What’s more, introducing new “keywords” to your classes (say event
for some UI stuff or table
for persistence) is just a matter of putting a new method on the right object.
Methods, methods, methods everywhere
September learns from how other extensible languages work. Here, the single unifying concept of the language is the method. Everything from Person.greet
to if
is just a method on some object, and almost every single expression you see in a September program is a method call.
2+3
means just calling method +
on 2
, with the 3
as its argument. while(...){...}
? The builtins
object has a handy while
method with some lazily evaluated parameters. Even a.property
makes use of the .
method in the Object
class.
The method call syntax is so flexible that it can mimic constructs usual in curly-brace OO languages closely enough that you can code without ever finding anything too strange. But, if you want to get your hands dirty and tweak things to your liking, this is easy too.
Summing up
Just to be clear, September is not intended to be the messiah that saves the oh-so-dreary world of programming languages. On the contrary - there are many existing languages that are perfectly fine and already a joy to use, and for me, September is first and foremost an experiment and a hobby. Until now, this has been a very rewarding project, and if by some accident the language turns out to be useful to other people beside me? Bonus!
If you’re interested, the best thing would be to keep your eye on this blog. Once I’ve introduced the why of the language, I intend to post some interesting stuff about the how, starting with how exactly do you make the call syntax extensible enough. If you’d like to check it out yourself, here is the bitbucket repository, but things are still very, very, very raw and most of the examples you have in this article will not work yet.
What works already is the until
example from the beginning of the post:
until := |?condition, body| {
while(!condition.resolve()) {
body.resolve();
};
};
In the end, no magic required - just a short, two-parameter function.
Edit: More comments/discussion on Reddit.