> I recently discovered a CPAN module called WhatIf > (http://search.cpan.org/author/SIMONW/Whatif-1.01/). This module has > the ability to provide rollback functionality for arbitrary code.
Crazy... I was just thinking about this for an experimental language called "Snapshot" I'm about to implement for my job. > I don't really understand continuations yet (although I'm reading up > on them), so perhaps they would allow this to be done trivially. > However, I think it would be very cool to roll this module into the > core language and provide the keyword support in core. This is what Larry wants with let subcall(); (from Appendix C of A6). It would be great to have it in the core, if it's feasable to implement. The way Snapshot will probably do it is have a "local mark" on all its variables. Then when a variable is set, it will set a field corresponding to that local mark, and append itself to the queue associated with that mark. Correspondingly, when it's accessed, it would instead return the value in the local mark if it has one. Then, upon success, it would go through that mark's queue and tell the variables to commit themselves (maybe onto another mark field, if the let is nested). Upon failure, it would go through the queue and tell them to rollback. This could be implemented with very little overhead for variables that don't ever get assigned to during a "hypothetical" state. > Is this feasible? What would the overhead costs be? I'm thinking about whether this could be done as a module in P6. If so, wow, what an extensible language. Maybe you could, by very early on overriding the builtin Scalar container. I'm not sure what implications that would have for variables declared C<int>, and such. Probably just wouldn't work for them. Like: our LocalMark @*LOCAL_MARK; class LocalMark { method add(Ref $in) { push @.set: $in; } method commit() { for @.set { .commit; } } method rollback() { for @.set { .rollback; } } has Ref @.set is Set; } my class NewScalar is Scalar { method STORE($newval is copy) { [EMAIL PROTECTED] = $newval; } method FETCH() { for @*LOCAL_MARK { return %.mark{$_} if %.mark.exists($_) } undef; } method commit() { [EMAIL PROTECTED] = [EMAIL PROTECTED]; } method rollback() { %.mark.delete(@*LOCAL_MARK[0]); } has %.mark is keyed(LocalMark); } Scalar := NewScalar; And then: sub { let foo(); } Turns into: sub { unshift @*LOCAL_MARK, new LocalMark; foo(); KEEP { @*LOCAL_MARK[0].commit; shift @*LOCAL_MARK; } UNDO { @*LOCAL_MARK[0].rollback; shift @*LOCAL_MARK; } } Or something. I think it's a very powerful concept at the language level, however. Luke