How do people learn code?
In the absence of some kind of teaching design document that helps get new programmers up to speed in a codebase (which there almost never is, really), they must do their learning in a very bottom-up way. They start with a line of code, and then they leverage their understanding of the language elements before them to get two pieces of information:
In the assembly days, (1) was easy because each asm instruction did something simple and brain-dead, and there was a small, constant set of instructions that you could learn and master. But (2) was hard because instructions could load data out of memory that could be referenced from anywhere; there was not necessarily any statement of spirit or purpose for 0x13F8, even if the author intended one (although frequently he did not, because he sucked).
Later on:
With typed languages (or mostly typed languages like C/C++), it gets harder to (1) tell what the line of code does, because each line is more powerful (i.e., represents more instructions) and also contains references to concepts you don't understand yet (types whose definitions you haven't read, variables whose uses you haven't tracked down). But (2) gets easier because there is more structure imposed, more requirements on the author to declare and define concepts like types and variables, and a known way for you to go and find the definitions you need to know.
With today's bolted-on language features:
With MetaObjectProtocols such as C++ operator overloading, or some more advanced types of language-, environment-, and semantics-altering constructs, (1) becomes much harder. The language itself becomes a moving target, because the semantics of even simple things like object creation or the assignment operator might be different, depending on what mode your environment or runtime has been put into. And poorly organized code can change the environment in unnecessary and pathological ways that are quite distant from the code that you are trying to understand.
If you've ever worked with programmers who think their code is "elegant", you know what I'm talking about. Try learning some code in a codebase where the dereference and method call ("*", "()", and "->") operators have been overloaded. What does "(*a)->run()" do? What did you get when you dereferenced a? For that matter, will the method call to run happen at all? Or will it be subverted? Shouldn't you just go home and have a brandy?
Languages that offer these features, while much more powerful, cannot enforce as much conceptual locality as can a simpler language. As such, clever programmers who are sensitive to these learnability issues will adopt a sensible, consistent way of using these features, or better yet, furnish a teaching document that explains the codebase from a top-down perspective so the reader is spared this nightmare. But inexperienced, egotistical, or insensitive programmers will use these features for EVIL.
In summary: if you are going to be working with a system that uses MetaObjectProtocol or other environment manipulation tools, work alone or make sure you are the least readability-sensitive programmer on the team.
-- RusHeywood
One adjustment to this...
A good programmer can build, using MetaObjectProtocol and OperatorOverloading and other such features, a really great tool that makes everybody's lives easier.
A not-so-good programmer can do EVIL things with them and make their life difficult and frustrating because their understanding of how to use the features, especially when they are first exposed to them, is not complete.
And you have to accept that the code needed to build the tools that use the advanced features may not be intuitively obvious. This is why it is best to fully develop and test the tool you create as if it was its own product before you can use it, so that the behaviour of the code is orthogonal and well-understood.
This is especially true for OperatorOverloading, being the environment manipulation I have the most experience with. You spend time and lose readability of your library classes in hopes of better coding speed and understandability when you are using the library classes in your code.
Inspired by a discussion of MetaObjectProtocols; also, a rant against OperatorOverloading.