When reading other people's code you now effectively
have to learn what "language" they use too.
That's well said, and in fact it's not uncommon to talk about Lisp's capacity for crafting the language to solve the problem at hand.
Paul Graham's essay "Programming Bottom-Up" explains it really really well:
"Experienced Lisp programmers divide up their programs differently. As well as top-down design, they follow a principle which could be called bottom-up design-- changing the language to suit the problem.
In Lisp, you don't just write your program down toward the language, you also build the language up toward your program. As you're writing a program you may think 'I wish Lisp had such-and-such an operator.' So you go and write it. Afterward you realize that using the new operator would simplify the design of another part of the program, and so on. Language and program evolve together. Like the border between two warring states, the boundary between language and program is drawn and redrawn, until eventually it comes to rest along the mountains and rivers, the natural frontiers of your problem.
In the end your program will look as if the language had been designed for it. And when language and program fit one another well, you end up with code which is clear, small, and efficient."
As others have pointed out, no more than unfamiliar classes and so forth.
In any language, you can think of programming as building mini languages to solve problems. You have nouns and verbs - types/classes/instances and methods/functions/operators. Lisp gives you those parts of speech and also lets you manipulate the fundamental grammar as well!
My experience with heavily metaprogrammed Ruby is that this story has a dark side. Yes, when language and program fit one another well, you end up with code which is clear, small, and efficient. That is true... until you need to add a new feature that was not accounted for in the language design. Now you have to wade into the code of the "compiler".
Abstraction generally gives up flexibility to obtain conciseness. Certainly a balance must be struck, but "not flexible enough" has caused me vastly more pain than "not concise enough". As a consultant who frequently wades into other people's code, I generally consider metaprogramming to be a scourge.
Paul Graham's essay "Programming Bottom-Up" explains it really really well:
"Experienced Lisp programmers divide up their programs differently. As well as top-down design, they follow a principle which could be called bottom-up design-- changing the language to suit the problem.
In Lisp, you don't just write your program down toward the language, you also build the language up toward your program. As you're writing a program you may think 'I wish Lisp had such-and-such an operator.' So you go and write it. Afterward you realize that using the new operator would simplify the design of another part of the program, and so on. Language and program evolve together. Like the border between two warring states, the boundary between language and program is drawn and redrawn, until eventually it comes to rest along the mountains and rivers, the natural frontiers of your problem.
In the end your program will look as if the language had been designed for it. And when language and program fit one another well, you end up with code which is clear, small, and efficient."
http://www.paulgraham.com/progbot.html
As others have pointed out, no more than unfamiliar classes and so forth.In any language, you can think of programming as building mini languages to solve problems. You have nouns and verbs - types/classes/instances and methods/functions/operators. Lisp gives you those parts of speech and also lets you manipulate the fundamental grammar as well!