Thanks again! By reducing to a simpler example, I now see that eval("$x + $y") and eval('$x + $y') are both evaluated by, er, eval.
I had played with eval originally because I thought eval($mw->Label(-text => "Col. 1", $opt, -padx => 10)->grid( ...) would substitute $opt with its contents, and in turn evaluate the entire string. I still don't understand the steps the interpreter takes when processing an eval, but it's probably not a fruitful path to pursue further at this time. Better that I understand now that since subroutines take lists as their argument, @opt is an appropriate means to convey list items. | [reply] |
I still don't understand the steps the interpreter takes when processing an eval
eval with a string argument basically does the same thing as perl when it parses and executes Perl code. The thing that can get confusing is exactly what the contents of that string are. Consider this: when you write $x=3; $y=2; print "$x + $y";, then you know that double quotes interpolate, in this case meaning that the current values of those variables are substituted into the string. What gets passed to the print function is the string "3 + 2". On the other hand, in print '$x + $y';, the single quotes don't interpolate, and the string that gets passed to the function is exactly '$x + $y'. Now substitute eval for print, and I hope it's clear what strings are being passed to the function: In the first case, eval is parsing and executing the Perl code 3 + 2, and in the second case, it's parsing and executing the Perl code $x + $y, with the current values of those variables. Although in this simple example the result may be the same, it can get very tricky very quickly, for example if the code and especially the contents of the variables get more complex, if the string to be evaled gets stored for later execution, and so on.
| [reply] [d/l] [select] |
Further to haukex's post++, here's an untested way your original approach might have been made to work. Please understand that I only suggest this for the purpose of experimenting to gain a better understanding of eval when you meet it again.
The basic idea here is to completely build and possibly check the eval string before passing it to eval.
my $newfont = ...;
my ($fg, $bg) = (..., ...);
my $opt = "-fg => $fg, -bg => $bg";
$opt .= ", -font => $newfont" if length $newfont;
my $eval_string = # note \$rw is escaped, $opt is NOT
qq{\$rw->Label(-text => "Col. 1", $opt, -padx => 10)->grid(
\$rw->Label(-text => "Col. 2", $opt, -padx => 11),
\$rw->Label(-text => "Col. 3", $opt, -padx => 11))
};
print "eval string '$eval_string' \n" if $DEBUG;
my $rw = ...; # tk object must exist before string is eval-ed
eval $eval_string;
Again, Don't Do This! in your Tk app: you'll give yourself a terrible headache. eval is powerful and can be very useful, but there's a time and place for everything.
Just to pound this completely into the ground, if $opt had been something that made sense to Label (so you didn't get the "Odd number of args ..." or any other error), why couldn't
eval($mw->Label(-text => "Col. 1", $opt, -padx => 10)->grid( ...));
work? It might, or at least it might appear to.
In the eval EXPR invocation above, the expression is
$mw->Label(-text => "Col. 1", $opt, -padx => 10)->grid( ...)
and the value passed to eval depends on whatever the call to grid() returns, which, IIRC, is nothing, the empty list (but I haven't checked this). In this case, the call to Label might work as expected when it was invoked during construction of the eval argument list, but when the (I think) empty argument list was then passed to eval, a perhaps puzzling Use of uninitialized value in eval "string" ... warning would be printed (if you had warnings enabled, which, as a righteous Monk, you always have :).
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |