I'm designing a fairly simplistic stack-based programming language, and implementing it in Python. (no link, because it's not fully implemented yet.)
The language itself is essentially intended to be the actually usable lovechild of Forth and Joy, but JIT-compiled (mainly so I can learn to write a compiler).
Being Python, there is no "Virtual Machine" to speak of in the normal sense, but the runtime is a communication between a stack machine (a module's worth of classes implementing various features) and the lexerless "parser" which really just turns bytes into function calls at runtime.
Real native code does not have an idea of exceptions (obviously, being physical instructions, they don't really care either way), but the kernel can tell when things get out of hand, and so it and the memmapper are in a way the handler for errors in platform-native code.
By the language's nature, a large portion of Python's control flow is implemented through exceptions and handling them. However, the stack machine is meant to closely resemble a real Stack Machine in that giving it bad instructions will get you a slap in the face. In my opinion while code littered with try; except; else
may well be Pythonic, sometimes it gets a bit much, especially if they're nested.
Do the exception handlers go nearest the raw data and functions, making them possibly easier to debug, or do they go alongside the (minimal) type-checking done by the runner, leaving the stack machine to be a Stupid Machine that returns None
sometimes?