Surprisingly I was only able to find one previous question on SO about this subject, and I\'d just like to get the community \"Vote of Confidence\" (or not!) on my approach.
I would say: use an exception if the bug is in someone else's code, or in code in a different subsystem (whether you wrote it or not). Also use an exception if there is an error in data that came from an external source such as a file.
Sometimes, you don't know whether the data came from an external source or not. If security is important and there's any possibility that you're dealing with external data that has not been verified correct, use an exception. If security is not important then I would use performance as a tiebreaker: might this code be executed in a tight loop? If so consider using an assert, as you'll get better performance in a Release build. Otherwise, use an exception.
My use of asserts follows ideas from design by contract. Basically, you assert that incoming parameters, globals variables and other state information is valid as you enter your function, and assert the return values and state is also valid as you leave. If you get a failed assert at the start, it is a bug in the calling code, if you get it at the end, the bug is in this code. These are pre-conditions and post conditions.
An assert in your switch statement is only really useful if you have checked your pre-conditions on entry. If you arrive at an unacceptable state in the middle of your function in this scenario, it is a failing in your function or a called function. Personally, I would stick with an assert here as it is not an exception. As you imply, exceptions relate to resources, not bugs. You can however create a custom assertion handler that exists in the release build and throws an exception on failure, to give your program an opportunity to return to a stable state.
In .Net, Debug class methods are not included in your program when you do make a release build, so you will have to throw an exception if this code makes it to production.
It depends on language, is assert if you syntax sugar then you should use it. however in Java asserts need to be turn on for this to work, so exception is better. However its always better to have specific exception, so here it should be IllegalStateException.
I agree with most people here and follow Design-by-Contract. You should try and differentiate very clearly between requirements in deployed code (Contracts) and figuring out expected state during design (Debugging Assertions).
You should ALWAYS throw contract assertions as exceptions (as they should always be exceptional). There are mechanisms built in to most frameworks for catching debug assertions. But at runtime you should always throw an exception.
I use a custom library to help with this (in C#/VB.NET). I recently put up it up on Codeplex (http://www.contractdriven.com/) if you're interested in how this works in practice.
A side benefit of this is that as you start using DbC more regularly, you seldom need to use debugging assertions as there are already explicit guarantees written in to your code, so it's actually difficult to get in to an invalid state.
So the question in your original post... "What I'm getting at here is that the user of MyClass has left it in an invalid state. So what should we do?"...should never arise.
You may never need to debug anything again! ;-)
I basically agree with the conclusion of your own question: if Alice's code detects a mistake Alice made, it's a case for Assert (and assertions should be left on in production code, unless performance dictates otherwise). If Alice's code detects a mistake in Eve's code, it's a case for Exceptions, assuming that Alice and Eve are on opposite sides of your bug-tracking software.
Now that's a general rule of thumb. Assertions, in a slightly modified form, can also be used as a "heads-up, developer!" mechanism (and then they should not be called "ASSERT" but "HEADS_UP" or something similar). What if your company develops a client/server product, and the server sends invalid data to the client? If you're a client programmer, you feel like treating it as external data (it is Eve's data that is kaputt) and you want to throw an exception. But a "softer" assertion, which makes Visual Studio's debugger halt right there, can be a very good way to detect those problems really early and report it to the server team. In a real installation, it could very well be Mallory tempering with the data between Eve and Alice, but most of the time it's really a bug by one of your colleagues, and you want to see it when it happens - that's why I call them "heads-up" assertions: they don't replace exceptions, but they give you a warning and a chance to inspect the problem.