Friday, December 3, 2010

Revision to php TCO trampoline

Sometimes I wake up at 6am with the frightful knowledge that there is an edge case to something I wrote somewhere which is incorrect. The only thing worse than knowing someone on the internet is wrong ( is knowing you were wrong on the internet.

I realized in a dream that my trampoline would not work with higher order functions as it currently stands because the while loop is based on is_callable, obviously if your function is meant to return a function you would not want it to be executed immediately (particularly because it probably expects arguments etc.). All of a sudden the whole throwing an exception approach made sense - however thanks to php5.3s __invoke method I can handle this cleanly by wrapping each tail call in an instance of TrampolineBounce and then check "$return instanceof TrampolineBounce".

I figured if I am going to need a Trampoline class I may as well leverage __callStatic to allow for easier invocation of trampolined functions. With out further ado:

namespace Trampoline;

class Bounce {
private $func;
public function __construct($func) {
$this->func = $func;

function __invoke() {
return call_user_func_array($this->func, array());

class Trampoline {
public static function Bounce($func) {
return new Bounce($func);

public static function __callStatic($func, $args) {
$return = call_user_func_array($func, $args);
while($return instanceof Bounce) {
$return = $return();

return $return;

function even($n) {
return $n == 0 ? true : Trampoline::Bounce(function() use($n) { return odd($n - 1);});

function odd($n) {
return $n == 0 ? false : Trampoline::Bounce(function() use($n) { return even($n - 1);});

echo Trampoline::even(1500) ? 'Yep' : 'Nope';


Gael Abadín said...
This comment has been removed by the author.
Richard C. Lambert said...

That is very cool...surfed in looking for info on big trampolines, but got caught up in your post. I'll definitely have to try it out. rectangle trampoline