There is something like this:

ПриВыходеИзВарпРежима() { ДобавитьКораблиВКосмос(); УстановитьУНихДефолтныеКоординаты(); ... ВключитьЩиты(); ОбнаружитьПротивников(); } 

There was an error in the ВключитьЩиты method, which means I want to roll everything back. With databases, everything is easy, there are transactions. And what about the code? Maybe they invented something? Not to write a bunch of reverse steps.

  • What exactly "everything" do you want to roll back? - Kromster

4 answers 4

Try to write your code in the style of "dangerous changes - secure commit" + immunity.

 // изменения локальные корабли' = создать корабли с дефолтными координатами и включённым щитом(); локальный космос' = космос.ДобавитьКораблиИВернутьНовыйКосмос(корабли'); ... локальные противники' = обнаружить противников в (космос'); // безопасный коммит космос = космос' противники = противники' 

If any part of the change takes off, it only affects local objects that are eaten by the garbage collector or RAII.


If all your objects are immutable, then the new local space is not a consumable thing: it shares most of its objects with the old space.

    To solve this problem, the Memento pattern ( Keeper ) is used.

    With it, you save the state of the object before starting operations. And in case of an error, write the saved state back.

    It remains only to catch the presence of an error. Win-win option - through return values. You can also use exceptions. But in this case they are not very relevant, since this is not even an exceptional situation at all, but quite a game logic. They only add extra brakes. And the logic is spread over the code no worse than goto does.

      It's not entirely clear what exactly you want to roll back. The state of variables changed in the method in which the error occurred?

      If so, then the easiest way is to save the state of all the variables you need before calling the ВключитьЩиты() method. Then, in case of an error, use return to the saved state.

        I saw this technique. Before executing the critical code, make a copy of all variables / objects. Then we execute the code. If an error occurs, then just restore everything back. In C ++, this can be done conveniently if you write the correct copy constructors.

        In pure C, I saw another method. Sly goto series. Somewhere like that.

         ПриВыходеИзВарпРежима() { if (!ДобавитьКораблиВКосмос()) { goto space; } if (!УстановитьУНихДефолтныеКоординаты()) { goto coord; } ... if (!ВключитьЩиты()) { goto guard; } if (!ОбнаружитьПротивников()) {goto anemi;} return ok; anemi: ПровестиДиагностикуВторогоУровня(); guard: ПерекалиброватьЩиты(); coord: УбратьДефолтныеКоординаты(); space: УбратьКораблиСКосмоса(); return bad; } 

        That is, if an error occurs - go on goto to handlers "rollback to normal".

        Yes, I see that you do not want to write "reverse steps", but sometimes it is simply impossible without them.