Massive improvements to Pigeon – Akka Actors for .NET


The last few weeks have been busy busy.
Me and Aaron have been making some massive improvements to Pigeon.
Most of the Akka features are now completed, remoting still needs some love and after that we will start porting Akka clustering.

One of the latest features we have added is logging.
We support the same features as real Akka, so logging can be done using the ActorSystem.EventStream, and there is also a BusLogging LoggingAdapter.

We are also leveraging the real Akka config, so we can enable logging based on the same configuration options that Akka has.
Here is a snapshot of the output from the StandardOutLogger when booting the ChatServer example:

2014-02-21 22:40:44 DebugLevel EventStream - subscribing [akka://all-systems/StandardOutLogger] to channel Pigeon.Event.Info [Thread 9]
2014-02-21 22:40:44 DebugLevel EventStream - subscribing [akka://all-systems/StandardOutLogger] to channel Pigeon.Event.Warning [Thread 9]
2014-02-21 22:40:44 DebugLevel EventStream - subscribing [akka://all-systems/StandardOutLogger] to channel Pigeon.Event.Error [Thread 9]
2014-02-21 22:40:44 DebugLevel EventStream - StandardOutLogger started [Thread 9]
2014-02-21 22:40:44 DebugLevel akka.tcp://MyServer@localhost:8081 - now supervising akka.tcp://MyServer@localhost:8081/user [Thread 10]
2014-02-21 22:40:44 DebugLevel akka.tcp://MyServer@localhost:8081 - now supervising akka.tcp://MyServer@localhost:8081/system [Thread 10]
2014-02-21 22:40:44 DebugLevel akka.tcp://MyServer@localhost:8081/system - now supervising akka.tcp://MyServer@localhost:8081/system/deadLetterListener [Thread 11]
2014-02-21 22:40:44 DebugLevel EventStream - subscribing [akka.tcp://MyServer@localhost:8081/system/deadLetterListener] to channel Pigeon.Event.DeadLetter [Thread 9]
2014-02-21 22:40:44 DebugLevel akka.tcp://MyServer@localhost:8081/system - now supervising akka.tcp://MyServer@localhost:8081/system/logMyServer-DefaultLogger [Thread 10]
2014-02-21 22:40:44 DebugLevel EventStream(MyServer) - Default Loggers started [Thread 11]
2014-02-21 22:40:44 DebugLevel EventStream - subscribing [akka.tcp://MyServer@localhost:8081/system/logMyServer-DefaultLogger] to channel Pigeon.Event.Error [Thread 11]
2014-02-21 22:40:44 DebugLevel EventStream - unsubscribing [akka.tcp://MyServer@localhost:8081/system/logMyServer-DefaultLogger] from channel Pigeon.Event.Debug [Thread 11]
2014-02-21 22:40:44 DebugLevel EventStream - unsubscribing [akka.tcp://MyServer@localhost:8081/system/logMyServer-DefaultLogger] from channel Pigeon.Event.Info [Thread 11]
2014-02-21 22:40:44 DebugLevel EventStream - unsubscribing [akka.tcp://MyServer@localhost:8081/system/logMyServer-DefaultLogger] from channel Pigeon.Event.Warning [Thread 11]
2014-02-21 22:40:44 WarningLevel ActorSystem(MyServer) - {
  akka : {
    log-config-on-start : on
    stdout-loglevel : DEBUG
    loglevel : ERROR
    actor : {
      provider : "Pigeon.Remote.RemoteActorRefProvider, Pigeon.Remote"
      debug : {
        receive : on
        autoreceive : on
        lifecycle : on
        event-stream : on
        unhandled : on
      }
    }
    remote : {
      server : {
        host : localhost
        port : 8081
      }
    }
  }
} [Thread 9]
2014-02-21 22:40:44 DebugLevel akka.tcp://MyServer@localhost:8081/user - now supervising akka.tcp://MyServer@localhost:8081/user/ChatServer [Thread 10]
2014-02-21 22:40:45 DebugLevel akka.tcp://MyServer@localhost:8081/user/ChatServer - received handled message ChatMessages.ConnectRequest [Thread 11]

Alot of the existing features have also been refined to conform even more to real Akka, e.g. ActorSelection have been rewritten to behave exactly like in Akka.
ActorRefs are now also serializable in messages, so you can send messages containing actorrefs across the wire and use them on remote systems.
The Akka RemoteDaemon is also coming along nicely, so we can create actors on remote nodes this way, the underlying deployment features are however not completed yet.

The Props class have also gotten new features, we can now configure dispatchers and mailboxes via the config and there is also a new dispatcher that lets you run actors in the main thread, to allow GUI updates in WPF/WinForms.

Well, there are alot of new features and bugfixes, so if you are interested in Actor Model Programming in .NET be sure to check out the Pigeon repository at https://github.com/rogeralsing/Pigeon

//Roger

 

More on Plastic


I’ve added some more features to my toy language “Plastic”.

Partial application of function arguments.
This is now used for generators.
Yield is no longer a core function, instead, each generator takes a closure as its last argument which is then supplied by the foreach function.
This way the foreach body don’t have to be stored as a symbol, it is just passed as an argument to the generator.

func Range(low,high,yield)
{
    for(let i=low,i<=high,i++)
    {
        yield(i);
    };
};

// apply value to "low"
let From10 = Range(10);

// apply value to "high"
foreach(x in From10(20))
{ //this block is transformed to a closure and passed to yield
    print(x);
};

Break and Continue
Loop behavior can now be altered with break and continue.
I implemented those as special values that breaks any execution flow almost like exceptions.
The values are then bubbled up to the first loop which consumes the values and perform the appropriate action.

I guess exceptions and “return” could be implemented the same way.

[Edit]

I’ve added some basic one way coroutine support to support breaking out of generators that are constructed from nested loops.
Before, a break would only exit the most inner loop of the generator.

Now I can do things like this:

func primes(low,high,yield)
{    
    foreach(i in range(low,high))   
    {             
         foreach(j in range(2,i/2))        
         { 
             if (i % j == 0)
             {
                break;
             };
         }
         else
         {  
             yield(i);
         };         
    }; 
};


foreach(prime in primes(2,100))
{
    print(prime);
    if (prime > 50,break);
}
else
{
    print(""done"");
};

Plastic – Added generator support


I’ve added generator support to my toy language “Plastic”.
It’s quite funny how easy it is to implement some language features once you understand how they work behind the scenes.
At first, I thought generators would be extremely hard to implement, requiring AST transformations to build state machines a’la C# for enumerable methods.

But my java script guru colleague Sebastian Markbåge stated “its simple, just invoke the for each body as a closure from the generator when you hit yield”.
It’s so brilliant, no AST transformations and I could implement the whole thing in less than 20 LOC.

This enables me to write code like this:

//a generator function
func Range(low,high)
{
    for(let i=low,i<=high,i++)
    {
        yield(i); 
    };
};

//loop over the generator values
foreach(x in Range(5,20))
{
    foreach(y in Range(1,2))
    {
        print ("yielded " + x + " " +y);
    };
};

Looks like a real language almost, doesn’t it? :-)

So what going on here?

Well, the foreach function creates a closure of its own body with a single in argument, this closure is then stored and the generator function is invoked.
Once the generator calls the “yield” function, the yield function will route the yielded value into the closure of the foreach body.
This works fine even for nested loops.

Playing with Plastic


As some of you might know, I’ve been fiddling with a generic DSL grammar, here and here.

I figured that I should do some proof of concept on this and started to write a language using the grammar and parser.
Since I’ve already created a LISP clone earlier, I thought I should go with something similair, but using my C like grammar.
The evaluator is beeing developed using F#, a wonderful language for this kinds of things, forget any bashing I’ve done on F# ;-)

The results of my experiments is a language that is somewhat similair to JavaScript, but with LISP’ish macro support.
I lie if I say it’s real macros, but I can get similair results as LISP macros.

How it works:

The C# based parser parses the source code and returns a generic AST.
I then use F# to translate the generic AST into a similair F# based AST, just to make it easier to consume it from F#
The F# AST is then passed to my F# evaluator, which simply traverses the AST and evaluates the branches in the AST.

F# does an amazing job here, the AST evaluator is only around 150 LOC and some 100 LOC for the core functions, like “if” and “func”.

With these 250 lines of code, I get features like:

Macro like functions:

func for(ref init,ref cond,ref step,ref body)
{
    init();
    let result = null;
    while(cond())
    {
        result = body();
        step();
    };
    result;
};

//makes it possible to do:
for(let i=0,i<3,i++)
{
    print(i);
};

Chained expressions:

The macro like support allows me to add new constructs to the language, unlike other languages
like Boo or Ruby where you can pass closures as the last argument to a function, I can pass an entire chain of functions or expressions as the tail argument.
thus allowing constructs like:

if(x)
{
}
elif(y)
{
}
else
{
};

Note that “;” terminates a chain, which is the reason why there is a “;” at the end of a “for” block for example.
This is the reason I picked the somewhat corny name “Plastic” for the language, because it can be molded to support new consturcts.

Passing functions:

//passing functions
func f(x)
{
    x + 3;
};

func g(function,x)
{
    function(x) * function(x);
};

print (g(f,7));

Returning functions(closures):

func makefun()
{
    let x = 10;
    func()
    {
        x++;
        print(x);
    };
};

let fun = makefun();
fun();
fun();
fun();

There is still lots of things I want to add, e.g. There is no OO support at all right now, nor is there any way to deal with simple things like arrays.
So there is more to come.