Hacker News new | ask | show | jobs
by alphaalpha101 3220 days ago
I don't really agree that it's inelegant to decide whether the reason for quitting is a success or an exception, or whether it's necessary. Like, you've either committed, in which case you shouldn't need to do any cleanup, or you haven't committed, in which case you need to clean up, right?

If you have an object representing some sort of transaction, and you just have actually-do-all-the-work-at-once-on-commit-being-called semantics, you don't actually need to do anything in your destructor at all, right?

    template<typename T>
    class transaction {
        std::vector<T> things_to_do;
    public:
        void add_work_item(T t) {
            things_to_do.push_back(t);
        }
        void commit() {
            for (auto t : things_to_do) {
                t.do();
            }
        }
    };
1 comments

You are just making my point with that OOP mess (sorry). You are not using RAII to finish (meaning cleanup or rollback) the transaction.

What we want actually executed in the end (in terms of control flow - not necessarily what we would be willing to code), is something like the following clean procedural code.

    do_some_foo():
        start_transaction()
        r = do_thing_A()
        if r == CONFLICT:
            rollback()
            return r
        r = do_thing_B()
        if r == CONFLICT:
            rollback()
            return r
        commit()
        return OK
There's nothing remotely object-oriented about what I wrote. I don't see any inheritance. I don't see any polymorphism. I don't see any virtual member functions.

And of course I'm using RAII to roll back the transaction. When the object is destroyed the vector is destroyed and the transaction isn't run.

It doesn't make any sense at all, quite frankly, to use RAII to do what you wrote there. That's not what RAII is for, nor is it what RAII is good at. RAII is for managing resources.