tags:

views:

198

answers:

4

Can you provide any examples where using eval EXPR is really necessary? I'm asking because its generally discouraged.

A: 

Quite a few years ago, I wrote a static web site generator which used Perl (<-- interesting that my spell checker suggests "Peril" as a replacement for that) as its scripting language. It allowed the user to enter information about different levels of a hierarchy - the first to market was for a cemetery where you had clients (paying customers) who owned memorials (for the deceased, obviously).

It had a GUI where you entered variables such as (tremble at my graphical skills here):

+------------+----------------------------+
| ClientName | Pax Diablo                 |
+------------+----------------------------+
| Address    | 666 Hades St, Washinton DC |
+------------+----------------------------+

and picture variables as well.

In addition, for each market (such as the afore-mentioned cemetery), there was a controlling script which basically ran and processed each record at multiple hierarchy levels to generate the static content. Before then, the program had turned all those variables into things like:

$Var{"ClientName"} = "Pax Diablo";

(I think that syntax is right, I haven't done any Perl development for a while). The end result was a full web site with lots of clients, lots of memorials, search pages and a nice little money earner while it lasted (I was blown out of the market by funeral directors providing the same thing as a 'free' service within their regular packages).

But the whole thing was basically written in minimal Perl which only did two things:

  • turned the variables into Perl assignment statements; and
  • ran the market-specific Perl code.

Both the execution of the assignment statements and the market-specific Perl code was done with eval.

So it's not as useless as you may think. It was a cheap way to introduce scripting into an application.

paxdiablo
I really, really don't think that loading configuration is a very good of eval
Leon Timmermans
That's a matter of opinion. The configuration allowed by the user was the tightly controlled variables which were checked thoroughly for injection attacks. The unchecked part was the market-specific code which was written by the developer anyway so no danger there. All in all, it worked quite well. Now I wouldn't let a user type in statements like "$x =7;" and eval them wildly - I think that's what you were getting at.
paxdiablo
+5  A: 

String eval is the only way to make new code out of strings. This is rarely necessary, but there are a few valid use cases, for example when converting templates to runnable code. Other than that, there are very few valid uses for it. eval "require $module_name" is a well known idiom, but using for example Module::Load is a better idea than that IMO.

Leon Timmermans
Just as explanation: eval "require $module_name" is needed instead of "eval { require $module_name }" because "require EXPR" tries to require a file while "require BAREWORD" (i.E. the evaluated sting in this eval) requires a module.
willert
+4  A: 
willert
There's usually no need to use `eval` to build classes dynamically; you can just muck about with the symbol table. I was genuinely surprised to see those `eval`s in Exception::Class, though. I wonder if any of them are truly necessary...
friedo
The eval statements are needed because Exception::Class relies on SUPER calls in a dynamically created class hierarchy. SUPER is bound to the current package's @ISA, so you can't call it from anonymous subs and naive symbol table manipulation falls flat. You could get around this, but it's not easy at all and IIRC no prepackaged alternative was around in 2000 when E::C was started.
willert
There is NEXT (search.cpan.org/perldoc?NEXT) for that (though it probably wasn't around in 2000).
Leon Timmermans
Yes, NEXT (mostly) solves this problem but adds a non-core dependency for perl version 5.6 or lower. Also, NEXT uses C3 method dispatching which differs significantly from perl's original DFS dispatcher. Additionally, NEXT is kind of deprecated, better have a look at MRO::Compat - http://search.cpan.org/dist/MRO-Compat/ if the trade-off in terms of non-core dependencies don't concern you.
willert
+5  A: 

String eval is the only way to:

  1. execute new code in a runtime decided package
  2. add overloading to a package at runtime (at least according to overload.pm)
  3. execute arbitrary strings of Perl
  4. compile macro type substitutions

String eval should not be used to:

  1. evaluate symbolic references
  2. execute any code from the user
  3. trap errors
  4. if there is any other way to do it

eval can also be used to create ad-hoc communication protocols between different systems or different languages that also have eval (provided that everything is secure of course. JSON can be seen as a more secure, but limited subset of this method)

Eric Strom