So the question comes up: What will Parrot's next generation control flow look like? What kinds of exotic control flow will be be able to support? What kinds should be aim to support? What kinds of cool new paradigms could we invent? We have Subroutines, Methods, Multimethods, Coroutines, Continuations, ExceptionHandlers and Closures. What can we get from combining these? What benefits can people see by being able to introspect Contexts and CallSignatures from running PIR code?
An ExceptionHandler Coroutine is one that I've been particularly interested in:
.sub 'WhenBadThingsHappen' :handles('foo')
say "One exception!"
say "Two exceptions!"
say "Too many exceptions!"
Syntax of course will vary, but you can see what I am planning there.
ExceptionHandler subroutines are going to need at least two possible resolutions: Either they properly handle the exception and resume normal control flow (by jumping to a preset resume Continuation or Sub), or they rethrow the exception. A rethrown exception moves to the next handler, and when there are no more handlers to catch it we exit the runloop and rethrow in the previous runloop (or exit with an unhandled exception if there are no more runloops).
In current ExceptionHandlers, we can use ".get_results" to get access to the thrown exception object only. What if ExceptionHandlers were instead curried Continuations that we could use to pass all sorts of arbitrary arguments to it?
$P0 = new ['ExceptionHandler']
push $P0, arg1
push $P0, arg2
We have a newclosure opcode which clones a sub and captures it's lexical scope. What if we had a newhandler opcode which cloned an existing sub, captured it's lexical scope, and marked it as a handler? That would allow us to use any arbitrary sub as an exception handler, treated as a lexically enclosed scope of the function where it is created?
With a little bit of work Contexts are going to be usable and introspectable from PIR code. Bacek has already done some work making data from Contexts visible to PIR code, which is a step in the right direction. What kinds of things will we be able to do with these, and what new things do we want? Manually manage registers? Iterate over registers like an array? Call another function but force it to use the same context (preinitialized registers)? Direct manipulation of control flow ("Jump up 3 call frames immediately")? Easy recursion of anonymous functions? Runtime creation and manipulation of LexPad and LexInfo? Change the current invocant object? Direct manipulation of the list of currently registered exception handlers? Redirect the call chain so we "return" to somewhere besides where we were called from?
That last idea is actually kind of fun, because you can start to think about Subs as being an intermediate step in a jump. "Go here, but do X on the way". I call a Sub, but the call gets intercepted by one of these filter functions and the parameter list is manipulated in a way that is invisible to both the caller and the callee. We can also start to think about PIR-based argument passing and processing. Need argument handling that Parrot doesn't provide natively? Write a small PIR argument preprocessor function and insert it invisibly into every function call!
This Saturday, 2 October, we're going to host a little PCC-related hackathon. A bunch of the Parrot hackers will be around, working on the PCC refactors branch, fixing PCC bugs, and hopefully implementing some long-awaited features. If you're a committer and have some time to hack on Saturday, we can use all the manpower we can get: Debugging and fixing test failures, profiling and optimizing codepaths, triaging and deleting old dead code, writing new tests to prevent regression, testing HLLs, and implementing new features. This will also be a great time for newcomers to get involved with Parrot too: Help out with a concerted development project, meet the developers, start getting your hands on the code, and start learning about one of Parrot's core mechanisms. A good time will be had by all!