Why don't developers switch from bitcoin-qt to a cleaner implementation? The "reference client" bitcoin-qt receives a lot of complaints from developers on the messy way it was coded.  It seems to require a big overhead to learn, and a lot of time is being spent on modularizing it.  Yet we have other implementations (bitcoinj, libbitcoin, etc)  that are already modular, and coded in a much clearer way.  Considering these facts, why wouldn't the developers switch their active development to one of these codebases?
(disclaimer: I work on Bitcoin Core)

As Luca already mentioned, you have to distinguish wallet implementations and the fully verifying nodes on the network. 

Because of how Satoshi wrote his code (a node and a wallet in the same program), the two are often confused, but this is considered a bad idea now. They can perfectly function independently. The reference client's wallet is only one of multiple wallets now, and certainly not the most used or in any privileged position.

When we're talking about validation on the network, things are more complex. Bitcoin is a consensus system, where every node in the network must be able to independently judge the validity of blocks, and come to the exact same conclusion as everyone else. If two nodes disagree about the validity of blocks, they will ignore the other (considering each other's blocks as attacks). If two groups of nodes with different rules both have mining power, a fork will appear, where both groups believe they're the only ones around. This is a disaster, as it means every coin that existed before the fork can be spent once on each side.

Thus, the actual rules of the network are those that full nodes implement. We can try do describe the behaviour, but can't prescribe it. If the rules would be written down in some unambiguous formal document, and a difference would be found between the rules and the implementation, we might say the implementation has a bug... but new nodes on the network would have to copy that bug nonetheless.

Unfortunately, reimplementing those rules is far from trivial. Many people who have tried doing so have actually discovered weirdnesses in what is considered valid by the reference client, and weren't previously known. For example, Bitcoin relies on OpenSSL for signature verification, and early versions just passed whatever was found in transactions to OpenSSL. Turns out that OpenSSL actually accepts incorrectly-encoded signatures to some degree. Without knowing it, several wallet implementation had appeared over time that created such signatures (they're accepted, they must be valid, right?). This means that any new fully validating node implementation must either use OpenSSL too, or mimick it exactly by accepting the exact same set of invalid encodings. There's been progress towards making these signatures invalid (since 0.8 they're not relayed anymore), but making them actually invalid will require a coordinated soft-fork of the consensus rules (EDIT: this has happened on july 4th 2015 with BIP66 being activated).

Examples such as that make me very uncertain about whether exact reimplementation is possible with the current state of the art. That's certainly partly due to implementation details in the reference client, but also because of how hard consensus systems are. There are unit tests for several parts of the logic, and a network interaction test that simulates several weird edge cases to see how a node responds, but they are far from complete (especially because maybe not all edge cases are even perfectly understood). Differences are unlikely to be things found through random testing.

In my opinion, we should aim at modularizing the reference client code, and abstracting the consensus-critical part out into a library, so that it can be reused by several clients without these risks. That will inevitably take time, though.