When is `eval` in Ruby justified?

笑着哭i 提交于 2019-12-27 17:37:21

问题


"Is 'eval' supposed to be nasty?" inspired this one:

Mostly everybody agrees that eval is bad, and in most cases there is more elegant/safer replacement.

So I wanted to ask: if eval is misused that often, is it really needed as a language feature? Is it doing more evil than good?

Personally, the only place I find it useful is to interpolate strings provided in config file.

Edit: The intention of this question is to get as many real-life cases as possible when eval is the only or the best solution. So please, don't go into "should a language limit a programmer's creativity" direction.

Edit2: And when I say eval, of course I refer to evaling string, not passing ruby block to instance_eval or class_eval.


回答1:


The only case I know of (other than "I have this string and I want to execute it") is dynamically dealing with local and global variables. Ruby has methods to get the names of local and global variables, but it lacks methods to get or set their values based on these names. The only way to do AFAIK is with eval.

Any other use is almost certainly wrong. I'm no guru and can't state categorically that there are no others, but every other use case I've ever seen where somebody said "You need eval for this," I've found a solution that didn't.

Note that I'm talking about string eval here, by the way. Ruby also has instance_eval, which can take either a string or a block to execute in the context of the receiver. The block form of this method is fast, safe and very useful.




回答2:


When is it justified? I'd say when there's no reasonable alternative. I was able to think of one use where I can't think of an alternative: irb, which, if you dig deep enough (to workspace.rb, around line 80 in my copy if you're interested) uses eval to execute your input:

def evaluate(context, statements, file = __FILE__, line = __LINE__)
  eval(statements, @binding, file, line)
end

That seems pretty reasonable to me - a situation where you specifically don't know what code you're going to have to execute until the very moment that you're asked to do so. Something dynamic and interactive seems to fit the bill.




回答3:


The reason eval is there is because when you need it, when you really need it, there are no substitutes. There's only so much you can do with creative method dispatching, after all, and at some point you need to execute arbitrary code.

Just because a language has a feature that might be dangerous doesn't mean it's inherently a bad thing. When a language presumes to know more than its user, that's when there's trouble.

I'd argue that when you find a programming language devoid of danger, you've found one that's not very useful.

When is eval justified? In pragmatic terms, when you say it is. If it's your program and you're the programmer, you set the parameters.




回答4:


There is one very important use-case for eval() which cannot (AFAIK) be achieved using anything else, and that is to find the corresponding object reference for a binding.

Say you have been passed a block but (for some reason) you need access to object context of the binding, you would do the following:

obj = eval('self', block.binding)

It is also useful to define the following:

class Proc
    def __context__
        eval('self', self.binding)
    end
end



回答5:


IMO mostly for Domain Specific Languages.

"Evaluation Options in Ruby" is an article by Jay Fields about it on InfoQ.




回答6:


eval is a tool, it is neither inherently good nor evil. It is justified whenever you are certain it is the right tool for what you are trying to accomplish.




回答7:


A tool like eval is about evaluating code at runtime vs. "compile" time. Do you know what the code is when you launch Ruby? Then you probably don't need eval. Is your code generating code during runtime? then you probably need to eval it.

For example, the methods/functions needed in a recursive decent parser depend on the language being parsed. If your application builds such a parser on-the-fly, then it might make sense to use eval. You could write a generalized parser, but it might not be as elegant a solution.

"Programatically filling in a letrec in Scheme. Macros or eval?" is a question I posted about eval in Scheme, where its use is mostly unavoidable.




回答8:


In general eval is a useful language feature when you want to run arbitrary code. This should be a rare thing but maybe you are making your own REPL or you want to expose the ruby run-time to the end user for some reason. It could happen and that is why the feature exists. If you are using it to work around some part of the language (e.g. global variables) then either the language is flawed or your understanding of the language is flawed. The solution is typically not to use eval but to either better understand the language or pick a different language.

It's worth noting that in ruby particulary instance_eval and class_eval have other uses.



来源:https://stackoverflow.com/questions/1902744/when-is-eval-in-ruby-justified

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!