"Code is strings" in exactly the same sense that "Speech is vibration of molecules."
The problem with eval-ing strings is that it doesn't scale. It's great for building three identical modules "B," "C," and "D," but the moment you want to do something interesting, it breaks down. The complexity of manipulating programs as strings grows far more rapidly than the complexity of things you want to do.
For example, String#to_proc adds some syntactic sugar to Ruby like implied parameters so you can write things like: some_array.map(&'+ 1'):
That's because it's trying to manipulate and eval strings that represent program syntax where it should be parsing the strings and manipulating data structures that represent program structure.
I'm not saying eval does scale, I'm just saying it's not evil. Of course, if I want to actually manipulate the parse tree, I should parse the string first. But if I don't need that kind of power, there's no sense in contorting my code to fit into the awkward metaprogramming constraints of <language>.
I (also) never said it was evil, I said it doesn't scale. But that being said, I have seen many tools start out being used just as you say, benignly, in places where they offer convenience for simple cases. Open classes a/k/a monkey patching falls in this category for me: a tool that works well for certain straightforward cases. However, programmers seem to have a reach that exceeds their grasp of the limitations of their tools, and over time people push the tools right out of their sweet spot and into trouble.
That's not the tool or technique's fault, of course. If people want to amend core classes with hundreds of kitchen-sink convenience methods or eval much more complex string manipulations... You might easily say that is the fault of the programmer for making a poor choice.
Reg, what's your take on the enhanced syntax that comes with PLT Scheme macros? Do those scale? The code in that isn't just a list, it also has contextually-meaningful information.
The problem with eval-ing strings is that it doesn't scale. It's great for building three identical modules "B," "C," and "D," but the moment you want to do something interesting, it breaks down. The complexity of manipulating programs as strings grows far more rapidly than the complexity of things you want to do.
For example, String#to_proc adds some syntactic sugar to Ruby like implied parameters so you can write things like: some_array.map(&'+ 1'):
http://github.com/raganwald/homoiconic/blob/master/2008-11-2...
The implementation is hideous:
http://github.com/raganwald/homoiconic/blob/master/2008-11-2...
That's because it's trying to manipulate and eval strings that represent program syntax where it should be parsing the strings and manipulating data structures that represent program structure.