Proposal: RAII for nested autodiff

I noticed a lot of the codebase contains block of the form:

  {
    try {
      start_nested();
      // Do stuff
    } catch (const std::exception& e) {
      recover_memory_nested();
      throw;
    }
    recover_memory_nested();
  }

This is error prone - some code paths have no try/catch logic (e.g. cvodes_ode_data.hpp, most uses in tests), some have additional logic around it (e.g. grad_hessian.hpp) others just vary whethere the start / recover calls are within or outside the try block (which AFAIK could be problematic in the rare case the start / recover itself causes an exception.

Maybe this would be better handled by creating a RAII class for nested autodiff, something like (code not tested):

class local_nested_autodiff {
public:
    local_nested_autodiff ()
    {
       start_nested();
    }
    ~local_nested_autodiff ()
    {
       recover_memory_nested();
    }
};

Which would let me write the code above as:

  {
    local_nested_autodiff nested();
    //Do stuff
  }

The cost is that such code is less readable for less experienced C++ users.

Any ideas?

4 Likes

This makes a lot of sense to me. My original proposals for parallel AD did do a very similar refactor.

I’d say go for it.

Does the RAII thing call the destructor if an error gets thrown?

Good catch

Yes. The RAII design as proposed will always clean things up in a safe way.

Yes. It is actually the recommended solution when people ask about the C++ equivalent of a finally keyword

Oh neat. I like this then.

That’s a really cool solution. I’ve never seen that pattern, but it makes a ton of sense. And as you can imagine, I was grumbling about the lack of Java-style finally the whole time I was writing the functionals.

1 Like

PR for review at: https://github.com/stan-dev/math/pull/1706

1 Like