Simon Wistow


Whatif - provides rollbacks, second chances and ways to overcomes regrets in code


  my $foo = "foo";

  whatif {    
    $foo = "bar";
  }; # foo is now "bar"

  whatif {
    $foo = "quux";
  }; # foo is still "bar", the call got rolled backed

  whatif {
    $foo = "yoo hoo!";
  } ifonly {
    $foo = "erk";
  }; # foo will be "yoo hoo"

  whatif {
    $foo = "here";
    die "Aaaargh\n";
  } ifonly {
    $foo = "there";
    print Whatif::ERR; # prints Aaaargh
  }; # foo will be "there"

  print Whatif::ERR; # also prints Aaaargh

  whatif {
  print Whatif::ERR; # prints undef

  $foo = "outer";
  whatif {
    $foo = "middle";
    whatif { $foo = "inner" };
  }; # $foo is "inner";

  $foo = "outer";
  whatif {
    $foo = "middle";
    whatif { $foo = "inner"; die };
  }; # $foo is "middle";


PLEASE NOTE the semi-colon after the whatif{}; block - without it you may get odd results;


Whatif provides database-like rollbacks but for code instead of database transactions. Think of whatif {} blocks as being like try{} catch{} blocks but on steroids.

Essentially, if you die within a whatif {} block then all code up until that point will be undone. Let's face it we all have regrets and if we can't solve them in software then where can we solve them?

But that's not all. Whatif not only provides a way out of that horrible 'OHMYGOD! What have I done?' moments but also gives you a second chance using our special sauce 'Guardian Angel[tm]' technology (patent pending).

Simply place an ifonly {} block after a whatif {} block and, should the whatif {} block fail, all the code in the ifonly {} block will be executed. Que convenient!

If only life itself could be like that.


This won't work on systems that don't have fork(). Sorry. I tried to come up with some code that worked by intercepting all writes to %:: but that just became a nightmare and Simon Cozens advised me against it. Then I tried something like

  void do_magic(SV* coderef)
        PerlInterpreter *orig, *copy;

        orig = Perl_get_context();
        copy = perl_clone(orig, FALSE);

        perl_call_sv(coderef, G_DISCARD|G_NOARGS|G_EVAL);

         /* Errk, it failed */
        if (SvTRUE(ERRSV)) {
                fprintf(stderr, "Errrrk\n");
        /* ooh, it was fine */
        } else {


but that would have only worked on threaded Perls (i.e 5.8) and, err, didn't work anyway. And after a few hours poking through perlguts and various websites I just went with the current approach.

This also won't work where you touch the world outside of Perl's control. Basically if you write something to a socket or a file or a DB then you're going to have to undo your mess yourself. That's what the ifonly{} block is for. There's nothing I can do about that. Deal.


Mark Fowler and I came up with the idea not, surprisingly, down the pub but whilst trying to sanitise the house we were moving out of. I imagine that the fumes probably had something to do with it and also suspect he deliberately planted the most crack fuelled idea he could think of into my brain, wound me up and let me go.

The current method of fork-ing was devised by Richard Clamp who basically gave me pretty much the whole module short of packaging it and providing the ifonly {} implementation. However he has more sense than I do.

Tom 'jerakeen' Insam helped with the perl_clone() testing by patiently typing in semi-lucid commands that I barked at him via IRC whilst I tried random things out without the benefit of my own threaded 5.8 box.

Matt 'hardest working man in perl' Sergeant's PPerl provided the code for setting readonly variables thanks to patches from the ever helpful Richard Clamp. This means that your PID stays the same even after a successful whatif {} block.

I'd also like to thank my make up stylist, my publisher and you, the fans for making all this possible.


(C)opyright 2002, Simon Wistow

Distributed under the same terms as Perl itself.

This software is under no warranty and will probably destroy your life, kill your friends, burn your house and bring about the apocalypse


Simon Wistow <>