Due to the shift from processors with higher frequencies to systems with multiple processors, cores, and hardware threads functional languages and especially Erlang gain higher attention. Unfortunately the special syntax based on the Prolog roots of Erlang scares many potentially interested developers. I personally can adopt new syntaxes relative fast, during the time I've developed in different languages like Pascal, Java, Python, Smalltalk, and Scheme. So it hasn't be a great problem to learn the Erlang syntax. The greater challenge is to think in concurrent working processes with asynchronous messages. But that's not the topic today.
The question is, how an alternative syntax for Erlang could look like to reach a greater audience? I already wrote here about doing OOP with Erlang. But that's not the best approach, it doesn't change the syntax. Today I think an alternate notation would be better. So lets try with a quick example as a basis for discussion. But before some preconditions:
- The designed language will not match Erlangs full feature richness, it's more a best-of-breed building some of the gen_server features direct into the language.
- Also it's no OO-language, it's concurrency-oriented with asynchronous messages between processes.
- It tries to be as functional as possible.
A code example:
module my_module {
/* Define a simple function. */
public function add(A1, A2) {
/* Each statements ends with a semicolon,
the last state determines the reply,
variables are only assignable once. */
A1 + A1;
}
/* Define a process. */
public process my_process {
/* Properties are addressable in each message
function, but they can only be changed once
there. */
property Name;
property SubProcess;
/* Init will be called automaticly when a
process is spawned. */
public message init() {
Name = none;
SubProcess = spawn_linked(another_process);
}
/* The number of spawn arguments can vary. The
adequate message function will be found through
matching. */
public message init(NewName) {
Name = NewName;
SubProcess = spawn_linked(another_process, Name);
}
/* Message functions use pattern matching and guards.
In this example, the sender will be notified
asynchronously. */
message set_name(NewName) when is_list(NewName) {
/* A dot is for synchronous messages. */
case (SubProcess.analyse_name(NewName))
ok : {
Name = NewName;
/* sender is predefined like self,
it's the sender of the currently
processed message. */
sender->name_set(NewName);
}
_ : {
/* An arrow is for asynchronous
messages. */
sender->invalid_name(NewName);
}
}
}
}
}
So far, so good. But some aspects are still open. First I would like to add hash maps. They are a powerful instrument for good readable code. So a message function could look like
public message withdraw(Booking) when Booking[amount] > 1000.0 {
case (self.get_balance(Booking[account]) > 1000.0) {
true : {
self->withdraw_checked(Booking);
ok;
}
false : {
{error, balance_too_low};
}
}
}
private message withdraw_checked(Booking) {
...
}
In case of a synchronous message the sender will receive either ok or {error, balance_too_low}. If this message has been sent asynchronously there would be no reply. You can also see that atoms and tuples should be like in Erlang, I also wouldn't change lists. Arrays are just maps with integers as keys. Public and private modifier determine if a (message) function is visible outside a module. So no more export statement is needed. The notation of higher order functions should be simplified a bit:
IoFun = $(Key, Value){io:format("~-20w = ~w~n", [Key, Value])};
maps:foreach(MyMap, IoFun);
I would do without pattern matching and guards here to be more simple. If this is needed the according functions should be defined - and well documented - and passed with a dollar sign:
private function foo({tuple, A}) { ... }
private function foo(A) when A =< 1000 { ... }
private function foo(A) when A > 1000 { ... }
lists:foreach(MyList, $foo);
These examples also show some Erlang conventions I would like to keep. Modules, processes, functions, and atoms are always named in small caps and underscores if needed. There's no mixed case, unlike in variables which are written starting with a capital letter and use mixed case.
This definition is by far not complete, but it is a cause for thought. So now I'm looking foreward to your responses.
2 Comments:
Hi there,
It is great to see someone open minded to a slight change in Erlang syntax for those of us who have had Object Orientation drilled into our heads from Day 1.
I get the idea of how you want to style the code, looks very promising indeed.
I mainly work in ABAP, Python and Java and I have been trying to get into Erlang for some time now. I think Erlang has fantastic promise for the future, I just wish I could get used to the syntax easier and that there was a better IDE. I have never liked Eclipse ;-)
I have also seen some interesting movements in Microsoft with F# etc...could there be anything in your mind where Erlang could learn from F# "syntax wise"? To me from an OO background I think F# looks easier? Maybe I am wrong....;-)
Great work Sir, it is so nice to see someone leading from the front!
Lynton
And, while you're at it, could you get rid of those semicolons, we have a \n there already.
Post a Comment