{ package AtomicState; # yucky name! sub new { my ($class) = @_; return bless({}, $class); } sub transaction { my ($self) = @_; return AtomicState::Transaction->new($self); } } { package AtomicState::Transaction; sub new { my ($class) = @_; my $obj_ref = \$_[1]; my $self = bless([ $obj_ref, undef ], $class); $self->commit(); return $self; } sub start_transaction { my ($self) = @_; my $backup = freeze($self); return AtomicState::Transaction->new($self); } # Multiple commits are allowed. sub commit { my ($self) = @_; $self->[1] = freeze(${$self->[0]}); } # Rolls back to the last commit, the first # being the creation of the the Transaction. sub rollback { my ($self) = @_; ${$self->[0]} = thaw($self->[1]); } sub DESTROY { my ($self) = @_; $self->rollback(); } } my $state = AtomicState->new(); { my $transact = $state->transaction(); $state->{a} = ...; push @{$state->{b}}, ...; $state{c}->{key} = ...; if (success) { $transact->commit(); } }