Exec() with 'return' keyword

I don’t need to imagine. I have multiple projects built on the model of live patching. And not one of them needs abnormal exception handling.

Live code editing is extremely hard to get right, if you don’t have a good framework to do it in. And that framework could take on a number of forms, but the one I invariably fall back on - due to its simplicity and ease of debugging - is the “core event loop” model. Generally speaking, these sorts of projects consist of a number of components.

  1. A kernel which does not ever get hot-reloaded. It handles basic initialization, then loads up all the other modules, and finally sets up the most basic event loop possible. In a Python project, that would probably end up dropping into an asyncio event loop or equivalent. In C, it’s probably something hand-rolled but would generally involve select()/epoll() and an event dispatch table. In Pike, I simply return -1 from main().
  2. A handful of core modules which provide crucial services to other modules. These modules make certain features available in some form of global registry. Some might set up socket servers or database connections, or even a GUI.
  3. “Leaf” modules that provide most of the user-facing functionality. As much as possible, these do not depend on each other. They use services from the core modules and get called from the central event loop. If something goes wrong, an exception is raised, and execution returns to the event loop.

This general three-tier model works fairly well for most of the projects I’ve built. And crucially, all debugging is done by returning to the main event loop after reporting an exception. In other words, standard try/except behaviour, just like you’d find in a typical Python web server or anything.

The beauty of it is that you don’t have to define the scope of what “caused trouble”; there are only a small handful of places that have exception-guard code (notably the core event loop, and sometimes there’ll be a separate one for services that can do better than the default). Everything else is simply built to keep returning to the main event loop.

Hackery to make statements skippable would not help with hot reloading.

Reversible debuggers, on the other hand, are extremely usable and useful; their main value is that they retain a lot of older state, not that they keep on executing. I don’t understand where you see a connection here, because reversible debuggers ONLY retain prior state, not future. If you can look at a crash report, then unwind the execution to see how things came to be the way they were, that’s effectively the same as recreating the problem but without having to recreate it. It is nothing to do with finding a way to “re-execute or cancel return statements”.

If you truly want a reversible debugger in Python, look into the trace feature and try retaining enough information to reconstruct the state.