5 ms·
Eval() Isn't Quite Pure Evil
- edw519 17y agoThe only thing missing from eval() is a keyboard shock to the programmer who tries to put a GOTO inside of it.
- fogus 17y agoIt does... except that the shock is lazy and is only felt by the next person trying to understand it.
- jrockway 17y agoWell, conference slides and large-scale applications are two different things. The advantage of the MOP manipulation is that it's composable. If you want to add another function to the module, you just call a method. If you want to make the process configurable, you take a callback as an argument and call it as you are building the module. It's just programming. eval, on the other hand, is limited to whatever string the programmer types in. This may be shorter for a conference slide, but probably more painful in Real Software.
- dnaquin 17y agoIs it just me or does the closure version read more clearly?
- pvg 17y agoIt seems the purpose was to show three module definitions and then and then talk about them - in which case both the eval and meta versions are complete gibberish since they have absolutely nothing to do with his expository goals. Both basically amount to 'let me show you some cute Ruby code that would generate the code that I could have just shown you on three slides. Instead of showing you three slides, though, I'd like you to become a Ruby interpreter for a few moments'. This seems almost purposefully obtuse. As to eval itself, it's obviously not 'evil'. But nontrivial use can make code unreadable: doSomeStuff() eval(someVar) doOtherStuff() this can be read as doSomeStuff() doPrettyMuchAnythingConceivable() doOtherStuff() This neatly removes any ability to effectively reason about the code.
- mr_dbr 17y agoThe first bit of code seemed perfectly readable.. Seems like decreasing the font size a few points would have clearer a better solution than clouding the could with loops and `eval()`/closures.. Depending on the context, perhaps showing the first class "full size", and abbreviating the other two would work.. or, show the code for one, then explain "we define another class named C, which prints C, and final one named D, which prints D" - it is a "talk", after all.. That's why I consider `eval` to be "evil" - there's almost always a better way..
- raganwald 17y agoI agree with the objection mentioned in the OP's comments: eval() as described turns code into strings. As Alan Perlis said: "The string is a stark data structure and everywhere it is passed there is much duplication of process. It is a perfect vehicle for hiding information." (You're tired of the canonical link, so here's a much more fun one: http://www.emacswiki.org/emacs/perlisisms.el http://www.emacswiki.org/emacs/perlisisms.el) Strings hide information, and string representations of programming languages hide the most important things about programs (with the possible exception of programming languages designed to manipulate strings, like SNOBOL). OTOH I like using ParseTree to convert Ruby programs into s-expressions and to Ruby2Ruby convert those s-expressions into strings before evaluating them. It's overkill at the moment, but somehow it seems to point towards something much, much better than strings: %w[B C D].each do |name| eval( Ruby2Ruby.new.process( s(:module, name.to_sym, s(:scope, s(:defn, :call, s(:args), s(:scope, s(:block, s(:call, nil, :puts, s(:arglist, s(:str, name)) ), s(:zsuper)) ) ) ) ) ) ) end It's ugly, but at least it tries to represent the structure of the Ruby code.
- leif 17y agoThat is so far from anything I would ever want to see on a slide (unless it's just meant to poke fun at such code), I don't even know where to begin. When you program, do you think of it as an exercise in bending your mind to the whim of the computer, or the other way around? I, for one, would rather make the computer understand what I'm thinking. If I'm thinking "hey, I want to evaluate this bit a bunch of times with different names", why can't I just say that? Isn't Ruby supposed to be the "English With Some Bits Of Punctuation" language? Assuming I've met any security concerns, and I'm not doing anything incredibly complicated (which, honestly, wouldn't pass code review with or without eval), what's wrong with writing the code the way I want? Looking at the author's received "fix", I don't understand it. I'm not a big fancy Ruby expert, but I've been through the poignant guide, I've written some medium-sized stuff with it, I've used most of the syntax constructs, and I think I get the idioms. The original makes sense; it's clear to me. We do three string format operations, and eval each one, thus defining a module each time. Great. The "fix" confuses me: "what's Module.new (I thought you just did 'module Name; stuff; end')?", "what's define_method (it looks like def, but why doesn't it just say def)?", "what's Object.const_set, and why don't I see 'name' until then?". With some reasonable inference, these aren't tough questions, but there remains one: "what the hell is the control flow diagram for this?". There are three anonymous functions defined in here, and I have no idea when the inner ones execute, or worse, are defined or compiled. I thought I understood Ruby's control flow, and I could make a guess at this, but there's no way I'd bet money on the result. So what if eval turns code into strings? Code _is_ strings! Do you think files are made of parse trees? eval doesn't hide information, it adds another level of abstraction (and there's an old saying about solving problems in computer science somewhere in there). Syntax highlighters, test coverage reports, static analyzers, and cyclomatic complexity calculators (really?) should all be able to handle it. Why? Because the feature is there, and it makes my life easier sometimes, and in those times, I want to use it. So, umm, there! That's what I think about eval.
- spc476 17y agoYeah, it's not evil ( http://boston.conman.org/2009/08/30.1 http://boston.conman.org/2009/08/30.1 ). Nope, not in the slightest ( http://boston.conman.org/2009/09/07.1 http://boston.conman.org/2009/09/07.1 ).
- rimantas 17y agoI think you have missed "quite" from the title, and this bit from the article: I hear two complaints most often when this talk comes up. The first is that eval() is dangerous. That usually means that we could take in some malicious code from a user and pass it into eval() where it would destroy our hard drive, or worse. Only, I'm not doing that. I made the variables here and user input is not involved. I think we're safe this time.
- joe_the_user 17y agoThe standard Ruby interpreter never releases memory to system once it allocates it. Ever. This is expected behavior. One of the founders of Twitter mentioned seeing an Engine Yard guy copy a 500 meg file from one machine to another. That instance of the interpreter allocated 500 megs and wouldn't let it go till it is killed. All this is the result of Ruby having to support Eval(). I love Ruby. I don't program in it anymore and I think that's tragic. I can see how Lisp is great just in the since that in a homoiconic language, eval is OK. But Ruby is nice and so much more intuitive, productive and beautiful and welcoming than those homoiconic langs. Perhaps this is why _why vanished... The Marcel Proust of the 21st century needs to write a tragic .... user's manual on the subject.
- jfoutz 17y agoSorry, maybe i'm just not thinking clearly this late at night. Why in the world is supporting eval related to hanging on to 500 megs of unused memory? Ruby is neat and all, but is there really anything in ruby that's not dressed up smalltalk? Squeak doesn't randomly hang on to 500m, afaik.
- calcnerd256 17y agoThe problem with eval is the principle of least power. He almost figured it out when he said it was too much tool for the job, but then he went on to useless metrics.
- lucumo 17y agoAs far as I can tell, the principle of least power[1] applies to descriptive languages (HTML, RDF, etc.) that are meant to store information. A program by comparison is meant to store instructions. I'm unsure about the argument you're making. Can you elaborate a bit? [1] For those that had to look it up like I had to: http://en.wikipedia.org/wiki/Principle_of_Least_Power http://en.wikipedia.org/wiki/Principle_of_Least_Power
- calcnerd256 17y agoI recommend treating it as a spectrum instead of boolean. Eval is considered harmful for a similar reason as to why GOTO is: it makes code harder to prove and to manipulate. Markup and data on one end of the spectrum can be endlessly manipulated, analyzed, and worked with. As we move up the power spectrum, we get to regular languages, stack languages, and finally Turing-completeness. Within Turing-completeness, though, there are still varying levels of how hard something is to work with. Yes, the halting problem means that you can't for any behavior determine whether an arbitrary program exhibits that behavior, but there are still subsets about which you can reason.
- cduan 17y agoThe practical problem with eval() is that people overuse it. This led me to once find a wonderful little code fragment written by a codeveloper that, when boiled down, was: eval(":" + symbol.to_s) which converted a symbol to a ... symbol.
- tetha 17y agoI'd figure that eval is in the same class as goto and for example Pythons vast dynamicness and metaprogramming abilities. Let's call this class the class of extremely powerful programming constructs. A GOOD programmer can use such an extremely powerful programming construct and write good, readable code with it which just makes you go 'wow, this is ... just clean, and I get what it does in a second', which is nicer than any code one might produce without using these tools, even though everyone knows that this class of control constructs can create a horrible mess. However, a BAD programmer can take this class of extremely powerful programming constructs, and create a horrible mess which requires more time to understand than a rewrite would take (more than once, probably). And now, the third fact you need to add into the mix is: Bad programmers usually don't think they are bad programmers. The realization 'I am actually a pretty bad programmer' is one major step on the path to being a good programmer, as absurd as it sounds. Thus, a good programmer will usually not use this class of extremely power programming constructs, because he knows that he will probably produce a mess with them (and probably miss some really nice solutions), while a bad programmer will probably use them happily, thinking he produces clean and nice code (but he is not). And this is the reason why gotos, evals and mind-bending meta-programming is not always bad, and not always evil, but we must not admit this, because otherwise, everyone will start using it :) (yes, I am aware that this is some sort of black/white-imaging and the solution is somewhere in the middle for everyone, but it shows the point much nicer)