Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/eval?V=77
QUERY_STRINGV=77
CONTENT_TYPE
DOCUMENT_URI/revision/eval
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR172.71.190.149
REMOTE_PORT26498
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR18.212.102.174
HTTP_CF_RAY86b838a718580582-IAD
HTTP_X_FORWARDED_PROTOhttps
HTTP_CF_VISITOR{"scheme":"https"}
HTTP_ACCEPT*/*
HTTP_USER_AGENTclaudebot
HTTP_CF_CONNECTING_IP18.212.102.174
HTTP_CDN_LOOPcloudflare
HTTP_CF_IPCOUNTRYUS

Body


Error

Unknow state transition: LINE -> END

-code

1

-level

0

-errorstack

INNER {returnImm {Unknow state transition: LINE -> END} {}} CALL {my render_wikit eval '''\[http://www.tcl.tk/man/tcl/TclCmd/eval.htm%|%eval\]''',\ a\ \[Tcl\ Commands%|%built-in\]\ Tcl\ \[command\],\ interprets\ its\ arguments\ as\ a\ \[script\],\nwhich\ it\ then\ evaluates.\n\n\n\n**\ Synopsis\ **\n\n\ \ \ \ :\ \ \ '''eval'''\ ''arg''\ ?''arg\ ...''?\ \ \n\n\n\n\n\n\ \ \ \[Injection\ Attack\]:\ \ \ \n\ \ \ \[introspection\]:\ \ \ \n\ \ \ \[Introspection\]:\ \ \ \n\ \ \ \[Many\ ways\ to\ eval\]:\ \ \ \n\ \ \ \[Many\ Ways\ to\ eval\]:\ \ \ \n\n\ \ \ \[try\]:\ \ \ can\ be\ used\ as\ \[bytecode%|%byte-coded\]\ alternative\ to\ `eval`\n\n\n\n\ \ \ \[http://www.tcl.tk/man/tcl/TclCmd/eval.htm%|%official\ reference\]:\ \ \ \n\n\n\n**\ Description\ **\n**\ Usage\ **\n\n`\[\[\[if\]\ 1\ ...\]`,\ which\ is\ byte-compiled,\ is\ an\ efficient\ replacement\ for\n`\[\[\[eval\]\]`\ in\ all\ cases.\ \ Thus,\ modern\ Tcl\ code\ has\ zero\ use\ for\ `\[\[eval\]`.\n\nTo\ avoid\ the\ caveats\ of\ `\[\[eval\]`\ the\ rule\ of\ thumb\ is\ to\ pass\ only\ one\nargument\ to\ `\[\[eval\]`.\ \ Passing\ a\ single\ script,\ rather\ than\ relying\ on\nimplicit\ concatenation\ helps\ to\ avoid\ dumb\ mistakes\ such\ as\ passing\ a\ string\nwhich\ contains\ newlines.\n\n\n\n\n'''`eval`'''\ concatenates\ its\ arguments\ in\ the\ same\ fashion\ as\n'''`\[\[eval\]`'''\ concatenates\ its\ arguments\ in\ the\ same\ fashion\ as\n`\[\[\[concat\]\]`,\ and\ hands\ them\ to\ the\ interpreter\ to\ be\ evaluated\ as\ a\ Tcl\nscript\ in\ the\ scope\ of\ the\ caller\ of\ \[\[`\[eval\]`\].\ \ It\ then\ returns\ the\ result\n\n`eval`\ is\ an\ old,\ old\ command\ that's\ been\ in\ \[Tcl\]\ from\ the\ beginning.\n`\[\[\[eval\]\]`\ is\ an\ old,\ old\ command,\ that's\ been\ in\ \[Tcl\]\ from\ the\ beginning.\n`eval`\ is\ useful\ when\ one\ wishes\ to\ generate\ a\ script\ and\ then\ interpret\ it.\n`\[\[eval\]`\ is\ useful\ when\ one\ wishes\ to\ generate\ a\ script\ and\ then\ interpret\ it.\nIn\ modern\ Tcl,\ `\[\[eval\]`\ is\ merely\ an\ abbreviation\ for\ `\[\[\[uplevel\]\ 0\]`.\ \ This\n'''self-modifying\ programs''',\ and\ related\ esoterica.\n\"self-modifying\ programs\",\ and\ related\ esoterica.\n`\[if\]\ 1\ ...`,\ which\ may\ be\ \[bytecode%|%byte-compiled\],\ is\ an\ efficient\nBecause\ the\ script\ is\ evaluated\ in\ the\ scope\ of\ the\ caller\ of\ \[\[`\[eval\]`\]\ a\nterminating\ command\ like\ \[\[`\[return\]`\]\ will\ cause\ the\ caller\ of\ \[\[`\[eval\]`\]\ to\n\n`eval`\ is\ used\ by\ \ all\ the\ commands\ --\ `\[bind\]`,\ everything\ with\n`\[\[eval\]`\ is\ used\ by\ \ all\ the\ commands\ --\ `\[\[\[bind\]\]`,\ everything\ with\n\nWhen\ using\ `eval`,\ it\ is\ very\ easy\ to\ leave\ holes\ which\ can\ be\ exploited\ to\nWhen\ using\ `\[\[eval\]`,\ it\ is\ very\ easy\ to\ leave\ holes\ which\ can\ be\ exploited\ to\ninject\ malicious\ code,\ so\ it\ is\ best\ to\ exercise\ extreme\ care\ with\ it\ until\ one\n\n`eval`\ can\ often\ be\ avoided,\ particularly\ with\ more\ modern\ recent\ versions\ of\n`\[\[eval\]`\ can\ often\ be\ avoided,\ particulary\ with\ more\ modern\ recent\ versions\ of\n\n\n\n**\ Eval\ and\ \[double\ substitution\]\ **\n**\ Eval\ and\ \[double\ subsitition\]\ **\n`eval`\ is\ one\ of\ the\ Tcl\ constructs\ that\ causes\ the\ Tcl\ interpreter\ to\n`\[\[\[eval\]\]`\ is\ one\ of\ the\ Tcl\ constructs\ that\ causes\ the\ Tcl\ interpreter\ to\nscan\ over\ its\ arguments\ another\ time\ and\ evalutate\ what\ it\ scans.\nGiven\ the\ following\ assignment,\n\n======\nset\ b\ \{the\ total\ is\ \$20\}\nset\ b\ \"the\ total\ is\ \$20\"\n\neach\ of\ the\ following\ commands\ returns\ a\ is\ different\ result:\neach\ of\ the\ following\ commands\ is\ subtly\ different:\n\nset\ a\ \$b\neval\ \{set\ a\ \$b\}\neval\ \"set\ a\ \$b\"\neval\ \[list\ set\ a\ \$b\]\n======\n\nConsider\ the\ first\ one,\n\n======\nset\ a\ \$b\n======\n\nPrior\ to\ invoking\ `\[set\]`,\ Tcl\ performs\ its\ substitutions,\ so\ the\ command\nPrior\ to\ invoking\ `\[\[\[set\]\]`,\ Tcl\ performs\ its\ substitutions,\ so\ the\ command\n\n======\n\ \ \ `set\ a\ \{the\ total\ is\ \$20\}`:\n`\[set\]`\ receives\ the\ arguments\ `a`,\ and\ `the\ total\ is\ \$20`,\ does\ not\ perform\n`\[\[\[set\]\]`\ receives\ the\ arguments\ `a`,\ and\ `the\ total\ is\ \$20`,\ does\ not\ perform\n`the\ total\ is\ \$20`.\n\nIn\ the\ second\ one,\ \n\n======\neval\ \{set\ a\ \$b\}\n======\n\nTcl\ does\ not\ perform\ any\ substitutions\ on\ the\ value\ in\ curly\ brackets,\ so\ the\nTcl\ does\ not\ perform\ an\ substitutions\ on\ the\ value\ in\ curly\ brackes,\ so\ the\ncommand\ remains\ unchanged.\ \ `\[\[\[eval\]\]`\ receives\ one\ argument,\n======\n\ \ \ `set\ a\ \$b`:\ \ \ \nwhich\ it\ then\ hands\ back\ to\ the\ interpreter.\ \ This\ time\ the\ interpreter\ sees\n`set\ a\ \$b`,\ which\ becomes:\n`set\ a\ \$b`,\ which\ becomes\n======\n\ \ \ `set\ a\ \{the\ total\ is\ \$20\}`:\ \ \ \nso\ the\ value\ of\ `\$a`\ becomes\ `the\ total\ is\ \$20`.\n,\ so\ the\ value\ of\ `\$a`\ becomes\ `the\ total\ is\ \$20`.\nIn\ the\ third\ example,\ \n\n======\neval\ \"set\ a\ \$b\"\n======\n\nTcl\ changes\ the\ command\ to\n\n======\n\ \ \ `eval\ \{set\ a\ the\ total\ is\ \$20\}`:\ \ \ \n`eval`\ receives\ the\ argument\n`\[\[\[eval\]\]`\ receives\ the\ argument\n======\n\ \ \ `set\ a\ Hello\ There`:\ \ \ \nand\ hands\ it\ to\ the\ interpreter\ for\ evaluation.\ \ This\ time,\ the\ interpreter\nsees\n\n======\n\ \ \ `set\ a\ the\ total\ is\ \$20`:\ \ \ \nfails\ to\ find\ the\ variable\ `\$20`\ and\ raises\ an\ error.\ \ If\ there\ had\ been\ no\n,\ fails\ to\ find\ the\ variable\ `\$20`,\ and\ raises\ an\ error.\ \ If\ there\ had\ been\ no\nvariable\ error,\ the\ interpreter\ would\ have\ invoked\ `\[\[\[set\]\]`\ with\ too\ many\narguments,\ causing\ `\[\[\[set\]\]\]`\ to\ raise\ an\ error.\n======\neval\ \[list\ set\ a\ \$b\]\n======\n\nTcl\ changes\ the\ command\ to\ `eval\ \{set\ a\ \{the\ total\ is\ \$20\}\}`,\ \ `\[set\]`\nTcl\ changes\ the\ command\ to\ `eval\ \{set\ a\ \{the\ total\ is\ \$20\}\}`,\ \ `\[\[\[set\]\]`\n`the\ total\ is\ \$20`.\n\n\n\nSee\ \[double\ substitution\]\ for\ the\ details\ of\ why\ it\ can\ be\ dangerous.\n\n\n**\ Is\ `eval`\ Evil?\ **\n**\ Is\ `\[\[eval\]`\ Evil?\ **\nShort\ answer:\ No.\ \ Like\ many\ commands\ in\ Tcl,\ `eval`\ can\ lead\ to\ \[double\nShort\ answer:\ No.\ \ Like\ many\ commands\ in\ Tcl,\ `\[\[eval\]`\ can\ lead\ to\ \[double\nskilled\ Tcl\ programmer\ knows\ how\ to\ wield\ \[double\ substitution\].\n\nHistorically,\ `eval`\ was\ often\ used\ with\ exec,\ to\ flatten\ lists,\ allowing\nHistorically,\ `\[\[\[eval\]\]`\ was\ often\ used\ with\ exec,\ to\ flatten\ lists,\ allowing\na\ single\ list\ to\ provide\ multiple\ arguments\ to\ a\ command:\ \n======\n#warning:\ no-longer\ recommended\neval\ exec\ grep\ foo\ \$filelist\n======\n\nbecause\ otherwise\ ''grep''\ would\ receive\ filelist\ as\ one\ long\ filename\ with\ embedded\ blanks.\nIn\ modern\ Tcl,\ the\ following\ is\ preferred:\nIn\ modern\ Tcl,\ the\ following\ is\ preferred\ for\ reasons\ of\ efficiency\ and\ safety:\nexec\ grep\ foo\ \{*\}\$filelist\n======\n\nOr,\ if\ you\ want\ to\ append\ one\ list's\ elements\ to\ another,\ and\ you're\ willing\ to\ assume\ that\ the\ variable\ containing\ the\ new\ elements\ doesn't\ embed\ any\ unquoted\ semicolons\ or\ newlines:\nembedded\ blanks.\ Or,\ if\ you\ want\ to\ append\ one\ list's\ elements\ to\ another:\n======\neval\ lappend\ thislist\ \$thatlist\nset\ thislist\ \[concat\ \$thislist\ \$thatlist\]\ \;#\ can\ also\ be\ done\ as\n======\n\nThough\ the\ following\ two\ options\ are\ safer\ and\ faster:\nstring)\ and\ finally\ calling\n\n======\neval\ \$script\n======\n\nWhen\ the\ script\ contains\ only\ one\ command,\ \[argument\ expansion\]\ is\ preferred:\n\n======\n\{*\}\$cmd\n======\n\n**\ Expanding\ Lists\ with\ `eval`\ **\n**\ Expanding\ Lists\ with\ `\[\[eval\]`\ **\nPrior\ to\ Tcl\ version\ 8.5,\ one\ use\ case\ for\ `eval`\ was\ to\ expand\ lists.\nPrior\ to\ Tcl\ version\ 8.5,\ one\ use\ case\ for\ `\[\[eval\]`\ was\ to\ expand\ lists.\nThere\ is\ no\ longer\ any\ reason\ to\ do\ this.\ \ Use\ `\[\{*\}\]`\ instead.\nSee\ \[Argument\ expansion\].\n\n----\nInstead\ of:\n\n\n======\n#warning:\ not\ recommended\neval\ pack\ \[winfo\ children\ .\]\n======\n\nuse:\n\n======\npack\ \{*\}\[winfo\ children\ .\]\n======\n\n----\n\nAnd\ instead\ of:\n\n======\n#warning:\ this\ is\ not\ recommended\nset\ filepath\ \[list\ path\ to\ the\ file\]\neval\ file\ join\ \$filepath\n======\n\nuse:\n\n======\nset\ filepath\ \[list\ path\ to\ the\ file\]\nfile\ join\ \{*\}\$filepath\n======\n\n----\nAnother\ similar\ example\n\n\n======\n#the\ old\ (bad)\ way\nset\ f\ \[glob\ *.tcl\]\neval\ \[linsert\ \$f\ 0\ exec\ lp\]\n======\n\n======\n#the\ shiny\ new\ way\nexec\ lp\ \{*\}\$f\n======\n\n\n***\ Historical\ ***\n\nThe\ following\ describes\ the\ situation\ before\ the\ advent\ of\ \[\{*\}\]:\n\nNaive\ code\ might\ look\ like\ this\ (an\ actual\ example\ from\ BWidget's\nentry.tcl:97):\n\n======\n#warning:\ bad\ code\ ahead!\neval\ entry\ \$path\ \$maps(:cmd)\n======\n\nAn\ unsuccessful\ attempt\ to\ fix\ the\ problem:\nAn\ unsuccesful\ attempt\ to\ fix\ the\ problem:\n======\n#warning:\ bad\ code\ ahead!\neval\ entry\ \[list\ \$path\]\ \$maps(:cmd)\n======\n\nBut\ `\$maps(:cmd)`\ might\ be\ a\ string\ with\ newlines:\n\n======\nset\ maps(:cmd)\ \{\n\ \ \ \ -opt1\ val1\n\ \ \ \ -opt2\ val2\n\}\n======\n\nIt's\ necessary\ to\ first\ convert\ `\$maps(:cmd)`\ to\ a\ proper\ list\ using\ one\ of\ the\nlist\ commands:\n\n======\neval\ \[linsert\ \$maps(:cmd)\ 0\ entry\ \$path\]\n======\n\n***\ See\ Also\ ***\n\n\ \ \ \[http://code.activestate.com/lists/tcl-core/414/%|%RE:\ TCLCORE\ Re:\ CFV:\ TIPs\ #156\ and\ #157\],\ \[Jeff\ Hobbs\],\ \[Tcl\ Core\ Team%|%tcl-core\ mailing\ list\],\ 2003-10-12:\ \ \ \[AMG\]:\ Text\ repeated\ below,\ please\ read\ it\ until\ you\ understand\ what\ trouble\ \[\[eval\]\]\ buys\ you\ and\ how\ helpful\ \[\{*\}\]\ is.\n\ \ \ \[http://code.activestate.com/lists/tcl-core/414/%|%RE:\ \[TCLCORE\]\ Re:\ CFV:\ TIPs\ #156\ and\ #157\]\ ,\[Jeffrey\ Hobbs%|%Jeff\ Hobbs\]\ ,\[Tcl\ Core\ Team%|%tcl-core\ mailing\ list\]\ ,2003-10-12:\ \ \ \n\ \ \ \[http://web.archive.org/web/20060325121839/http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/1748289%|%TCLCORE\ TIP\ #144:\ Argument\ Expansion\ Syntax\],\ \[Jeff\ Hobbs\],\ \[Tcl\ Core\ Team%|%tcl-core\ mailing\ list\],\ 2003-07-26:\ \ \ \n\ \ \ \[http://web.archive.org/web/20060325121839/http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/1748289%|%TCLCORE\ TIP\ #144:\ Argument\ Expansion\ Syntax\]\ ,\[Jeffrey\ Hobbs%|%Jeff\ Hobbs\]\ ,\[Tcl\ Core\ Team%|%tcl-core\ mailing\ list\]\ ,2003-07-26:\ \ \ \n\n\ \ \ \[http://groups.google.com/group/comp.lang.tcl/browse_thread/thread/c3d6651005e12629/a9dc3e05d95b0f12?hl=en&ie=UTF-8&q=argument+expansion+apply+variadic+group:comp.lang.tcl*#%|%eval\ is\ evil\ (for\ spreading\ list-arguments)\]\ ,\[comp.lang.tcl\]\ ,2003-03-11:\ \ \ \n****\ Re:\ CFV:\ TIPs\ #156\ and\ #157\ ****\n\n***\ Re:\ CFV:\ TIPs\ #156\ and\ #157\ **\n\n\[AMG\]:\n======none\n>\ miguel\ sofer\ <mig@ut...>\ writes:\n>\ >\ In\ tcllib,\ every\ effort\ is\ done\ to\ provide\ code\ that\ runs\ \n>\ >\ conditionally\ on\ the\ tcl\ version\ and\ provides\ the\ new\ functionality\ \n>\ >\ toold\ interpreters.\n>\ \n>\ But\ the\ TIP\ doesn't\ specify\ any\ new\ functionality.\ \ It\ only\ \n>\ specifies\ a\ new\ syntax\ for\ functionality\ that\ we\ already\ \n>\ have.\ \ I\ don't\ see\ a\ need\ to\ complicate\ code\ by\ providing\ two\ \n>\ implementations,\ when\ one\ of\ the\ implementations\ (the\ old\ \n>\ one)\ works\ on\ all\ versions\ of\ Tcl\ and\ has\ no\ functional\ drawbacks.\n\nAlright,\ this\ is\ where\ I\ step\ in\ to\ note\ how\ important\ this\ change\ is,\nand\ to\ correct\ everyone's\ completely\ false\ assumption\ that\ the\ existing\neval\ hell\ has\ no\ functional\ drawbacks.\ \ dgp\ asked\ me\ to\ post\ these\npoints\ that\ I\ made\ at\ Tcl2003\ earlier,\ but\ I\ didn't\ think\ it\ necessary.\nIt\ obviously\ is.\ \ It\ goes\ a\ little\ something\ like\ this:\n\nRaise\ your\ hand\ if\ you\ think\ this\ is\ correct:\n\n\ \ \ \ \ \ \ \ eval\ entry\ \$path\ \$args\n\nEveryone\ raising\ their\ hand\ please\ sit\ down.\ \ You\ are\ wrong.\ \ The\ \$path\narg\ will\ be\ split\ apart\ as\ well,\ which\ is\ bad\ when\ using\ this\ in\ low\nlevel\ code,\ like\ megawidgets\ or\ the\ like,\ where\ it\ must\ be\ handled\ncorrectly.\ \ After\ all,\ widgets\ with\ spaces\ in\ the\ names\ is\ 100%\ valid.\n\nOK,\ so\ we\ know\ the\ fix,\ right?\n\n\ \ \ \ \ \ \ \ eval\ entry\ \[list\ \$path\]\ \$args\n\nAh,\ that's\ better\ ...\ but\ something\ is\ not\ right.\ \ Hmmm\ ...\ oh,\ it\ is\ninefficient!\ \ The\ mix\ of\ list\ and\ string\ args\ will\ walk\ the\ wrong\ path\nfor\ optimization\ (this\ isn't\ important\ to\ everybody,\ but\ good\ low\ level\ncode\ writers\ should\ be\ sensitive\ to\ this).\ \ OK,\ so\ that\ means\ this\ is\nthe\ best,\ right?\n\n\ \ \ \ \ \ \ \ eval\ \[list\ entry\ \$path\]\ \$args\n\nNow\ I\ feel\ better.\ \ What,\ that's\ not\ right?\ \ If\ string\ args\ is\ actually\na\ multiline\ string,\ it\ won't\ work\ as\ expected.\ \ Try\ it\ with:\n\n\ \ \ \ \ \ \ \ set\ args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ -opt1\ val1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ -opt2\ val2\n\ \ \ \ \ \ \ \ \}\n\nand\ unfortunately\ that\ isn't\ theoretical.\ \ I've\ seen\ code\ that\ uses\ a\n\$defaultArgs\ set\ up\ like\ that\ before\ regular\ args\ to\ handle\ defaults.\n\nUgh\ ...\ what\ are\ we\ left\ with?\ \ This:\n\n\ \ \ \ \ \ \ \ eval\ \[linsert\ \$args\ 0\ entry\ \$path\]\n\nOnly\ the\ final\ version\ is\ 100%\ correct,\ guaranteed\ not\ to\ blow\ when\ you\nleast\ want\ it\ to.\n\nSo\ we\ get\ back\ to\ the\ original\ point\ ...\ eval\ itself\ may\ not\ be\nfunctionally\ flawed,\ but\ 99%\ of\ eval\ uses\ are.\ \ In\ fact\ I\ don't\ always\nuse\ the\ final\ solution\ in\ code\ because\ it\ can\ get\ so\ unwieldly,\ but\ now\nlet\ me\ focus\ on\ tcllib,\ which\ was\ mentioned.\ \ First\ let\ me\ say\ that\ my\nfavored\ solution\ is\ so\ much\ easier\ to\ use,\ has\ a\ minimal\ ugly\ factor,\nand\ doesn't\ have\ any\ of\ the\ flaws\ above:\n\n\ \ \ \ \ \ \ \ entry\ \$path\ \{*\}\$args\n\nSo\ on\ to\ tcllib.\ \ I\ just\ grep\ the\ .tcl\ files\ for\ \"eval\"\ and\ let\ me\npick\ a\ few:\n\n#\ I\ sure\ hope\ critcl\ isn't\ in\ a\ dir\ with\ a\ space\n./sak.tcl:\ \ \ \ \ \ \ \ eval\ exec\ \$critcl\ -force\ \\\n\ \ \ \ \ \ \ \ -libdir\ \[list\ \$target\]\ -pkg\ \[list\ \$pkg\]\ \$files\n\n#\ Isn't\ this\ beautifully\ easy\ to\ understand?\n./modules/ftp/ftp.tcl:\ \ \ \ \ \ \ \ eval\ \[concat\ \$ftp(Output)\ \{\$s\ \$msg\ \$state\}\]\n\n#\ I\ sure\ hope\ they\ don't\ use\ namespaces\ with\ spaces,\ or\ cmds\ ...\n./modules/irc/irc.tcl:\ \ \ \ \ \ eval\ \[namespace\ current\]::cmd-\$cmd\ \$args\n\n#\ hmmm,\ just\ looks\ dangerous\ ...\n./modules/struct/record.tcl:\ \ \ \ eval\ Create\ \$def\ \$\{inst_\}.\$\{inst\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$cnt_plus\]\n\n#\ I'm\ not\ sure\ why\ eval\ was\ used\ here.\n#\ I\ think\ because\ version\ can\ be\ empty?\n./modules/stooop/mkpkgidx.tcl:\ \ eval\ package\ require\ \$name\ \$version\n\n#\ I\ think\ someone\ needs\ to\ look\ up\ \"concat\"\n./modules/textutil/adjust.tcl:\ \ lappend\ list\ \[\ eval\ list\ \$i\ \$words(\$i)\ 1\ \]\n\nOK\ ...\ so\ I'm\ tired\ of\ looking\ now.\n\n\ \ Jeff\ Hobbs\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ The\ Tcl\ Guy\n\ \ Senior\ Developer\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ http://www.ActiveState.com/\n\ \ \ \ \ \ \ \ Tcl\ Support\ and\ Productivity\ Solutions\n======\n\n\n**\ Caveat:\ List-Like\ Strings\ **\n\nThe\ arguments\ to\ `eval`\ are\ concatenated\ into\ a\ string\ to\ be\ interpreted,\ but\nThe\ arguments\ to\ \[\[eval\]\ are\ concatenated\ into\ a\ string\ to\ be\ interpreted,\ but\n(i.e.,\ one\ conforming\ to\ the\ Tcl\ parsing\ rules\ as\ laid\ out\ in\ the\ Tcl\ manual\npage).\n\nThe\ following\ script\ breaks\ because\ the\ concatenation\ keeps\ the\ newlines\ from\nthe\ list's\ string\ representation,\ making\ `eval`\ interpret\ the\ second\ element\nthe\ list's\ string\ representation,\ making\ \[\[eval\]\]\ interpret\ the\ second\ element\n\n======none\n%\ set\ arg\ \{a\nb\nc\n\}\na\nb\nc\n%\ eval\ list\ \$arg\nambiguous\ command\ name\ \"b\":\ bgerror\ binary\ break\n======\n\nTo\ solve\ this,\ construct\ the\ argument\ using\ list\ primitives\ like\ `\[lappend\]`,\nTo\ solve\ this,\ construct\ the\ argument\ using\ list\ primitives\ like\ \[lappend\],\n\[list\],\ etc.\ \ DKF\ says:\ \ \"list\ and\ eval\ are\ truly\ made\ for\ each\ other.\"\nAnother\ solution\ is\ to\ use\ the\ following\ idiom:\n\n======none\n%\ eval\ \[linsert\ \$arg\ 0\ list\]\na\ b\ c\n======\n\n`\[linsert\]`\ converts\ its\ list\ argument\ to\ a\ well-formed\ list\ with\ single\n`\[\[\[linsert\]\]`\ converts\ its\ list\ argument\ to\ a\ well-formed\ list\ with\ single\nof\ these\ elements\ contain\ newlines,\ they\ remain\ in\ the\ resulting\ string).\n\nIt's\ important\ to\ remember\ that\ `eval`\ works\ on\ '''strings''',\ not\ lists,\nIt's\ important\ to\ remember\ that\ `\[\[\[eval\]\]`\ works\ on\ '''strings''',\ not\ lists,\nfor\ interpreting\ a\ string\ as\ a\ script.\n\n\n**\ Verbose\ Evaluation\ **\n\n\[LV\]:\ I\ just\ had\ to\ copy\ this\ over\ to\ the\ wiki\ -\ it\ is\ so\ neat!\n\nFrom\ comp.lang.tcl,\ \[Bob\ Techentin\]\ writes\ in\ response\ to\ a\ poster:\n\nIt\ sounds\ like\ you're\ looking\ for\ something\ similar\ to\ /bin/sh\ \"set\ -v\"\ command\nwhich\ prints\ shell\ input\ lines\ as\ they\ are\ read,\ and\ \"set\ -x\"\ which\ prints\nexpanded\ commands.\ \ Kind\ of\ like\ a\ verbose\ mode.\n\nNope.\ \ Nothing\ like\ that.\ \ But\ you\ wouldn't\ have\ to\ write\ your\ own\ shell.\ \ You\ncould\ walk\ through\ a\ script\ (a\ list\ of\ lines),\ and\ use\ `\[info\ complete\]`\ to\ncould\ walk\ through\ a\ script\ (a\ list\ of\ lines),\ and\ use\ `\[\[\[info\ complete\]\]`\ to\ncommand\ and\ the\ command's\ results.\ \ This\ seems\ to\ work.\n\n======\nproc\ verbose_eval\ \{script\}\ \{\n\ \ \ \ set\ cmd\ \{\}\ \n\ \ \ \ set\ cmd\ \"\"\n\ \ \ \ if\ \{\$line\ eq\ \{\}\}\ \{continue\}\n\ \ \ \ if\ \{\$line\ eq\ \"\"\}\ \{continue\}\n\ \ \ \ \ \ \ \ if\ \{\[info\ complete\ \$cmd\]\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\ \[info\ complete\ \$cmd\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \[uplevel\ 1\ \$cmd\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ cmd\ \"\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nset\ script\ \{\n\ \ \ \ puts\ hello\n\ \ \ \ expr\ \{2.2\ *\ 3\}\n\ \ \ \ expr\ 2.2*3\n\nverbose_eval\ \$script\ \n======\n\n\[LV\]:\ This\ proc\ is\ so\ slick!\ I\ love\ it!\n\[LV\]\ This\ proc\ is\ so\ slick!\ I\ love\ it!\n\[Lars\ H\]:\ \ Another\ approach\ to\ this\ (which\ also\ can\ see\ individual\ commands\ in\n`\[if\]`\ branches,\ loop\ bodies,\ etc.)\ is\ to\ use\ `\[trace\]`s.\ Do\ we\ have\ that\ written\n\[if\]\ branches,\ loop\ bodies,\ etc.)\ is\ to\ use\ \[trace\]s.\ Do\ we\ have\ that\ written\n\n\[AR\]\ Here\ is\ my\ proposal\ with\ traces.\ Rem:\ the\ \"noop\"\ string\ is\ some\ kind\ of\ magic\ cookie.\n\n\n\[wtracy\]\ 2008-06-23:\ I\ want\ the\ commands\ I\ run\ in\ eval\ to\ have\ their\ own\ set\ of\nvariables\ independently\ of\ the\ calling\ script.\ Is\ there\ some\ way\ I\ can\ hand\neval\ a\ context\ (maybe\ as\ an\ associative\ array?).\n\n\[Lars\ H\]:\ Sounds\ like\ you\ want\ a\ \[lambda\]\ (or\ possibly\ a\ \[closure\],\ which\ is\nmore\ difficult).\ If\ you're\ using\ Tcl\ 8.5,\ then\ have\ a\ look\ at\ `\[apply\]`.\nmore\ difficult).\ If\ you're\ using\ Tcl\ 8.5,\ then\ have\ a\ look\ at\ `\[\[\[apply\]\]`.\n\[RS\]:\ Long\ before\ 8.5,\ you\ could\ always\ write\ a\ little\ proc\ to\ hide\ its\ local\nvariables\ (x\ in\ this\ example):\n\n======none\n%\ eval\ \{proc\ \{\}\ x\ \{expr\ \{\$x*\$x\}\}\;\ \{\}\ 5\}\n%\ eval\ \{proc\ \{\}\ x\ \{expr\ \$x*\$x\}\;\ \{\}\ 5\}\n======\n\n\[wtracy\]:\ Thanks.\ It\ looks\ like\ `\[apply\]`\ is\ the\ closest\ Tcl\ feature\ to\ what\n\[wtracy\]:\ Thanks.\ It\ looks\ like\ `\[\[\[apply\]\]`\ is\ the\ closest\ Tcl\ feature\ to\ what\n\n\[wtracy\]:\ Actually,\ it\ looks\ like\ what\ I\ *really*\ want\ is\ to\ nest\ `eval`\n\[wtracy\]:\ Actually,\ it\ looks\ like\ what\ I\ *really*\ want\ is\ to\ nest\ `\[\[eval\]`\ninside\ of\ a\ `\[\[\[namespace\ eval\]\]`\ block.\n\[wtracy\]:\ Okay,\ for\ the\ sake\ of\ any\ lost\ soul\ that\ comes\ along\ after\ me,\ this\nis\ what\ I\ really\ wanted\ to\ do\ all\ along:\n\n======none\n\$\ set\ cmd\ \{puts\ FOO\}\n>\ set\ cmd\ \{puts\ FOO\}\n\$\ namespace\ eval\ MyNameSpace\ \$cmd\n>\ namespace\ eval\ MyNameSpace\ \$cmd\n======\n\n\[NEM\]:\ As\ mentioned,\ `\[apply\]`\ is\ probably\ a\ better\ choice\ in\ this\ case\ as\ it\n\[NEM\]\ As\ mentioned,\ `\[\[\[apply\]\]`\ is\ probably\ a\ better\ choice\ in\ this\ case\ as\ it\n\[dangers\ of\ creative\ writing\]\ for\ some\ related\ discussion.\ The\ `\[apply\]`\ version\ is:\n\[dangers\ of\ creative\ writing\]\ for\ some\ related\ discussion.\ The\ apply\ version\ is:\n======\napply\ \{\{\}\ \{puts\ FOO\}\ ::MyNameSpace\}\napply\ \{\{\}\ \{\ puts\ FOO\ \}\ ::MyNameSpace\}\n\nThis\ has\ the\ benefit\ of\ evaluating\ the\ code\ within\ a\ fresh\ procedure\ context,\nmeaning\ all\ variables\ are\ local\n\nto\ that\ context\ by\ default.\ See\ also\ `\[namespace\ inscope\]`/`\[namespace\ code\]`\ and\nto\ that\ context\ by\ default.\ See\ also\ \[namespace\ inscope\]/\[namespace\ code\]\ and\nyou\ may\ also\ like\ \[dict\ with\].\n\n**\ Proposal:\ Modify\ `eval`\ to\ Accept\ a\ List\ of\ Lists\ \ **\n**\ Proposal:\ Modify\ `\[\[eval\]`\ to\ Accept\ a\ List\ of\ Lists\ \ **\nIn\ some\ cases\ `eval`\ does\ work\ on\ lists\ -\ and\ its\ special.\ \ In\ particular,\nIn\ some\ cases\ `\[\[\[eval\]\]`\ does\ work\ on\ lists\ -\ and\ its\ special.\ \ In\ particular,\nif\ eval\ is\ passed\ a\ \[pure\ list\]\ then\ it\ gets\ evaluated\ directly,\ without\nwhat\ it\ ''could''\ be.\n\nWhen\ you\ pass\ eval\ a\ pure\ list,\ you\ can\ only\ execute\ a\ single\ command.\ \ What\ if\nwe\ were\ to\ pass\ eval\ a\ list\ of\ pure\ lists\ -\ it\ should\ directly\ evaluate\ each\ of\nthem,\ and\ return\ the\ value\ of\ the\ the\ last\ one\ evaluated.\ \ This\ sounds\ a\ lot\nlike\ progn\ in\ \[lisp\],\ and\ it\ seems\ like\ it\ would\ allow\ for\ some\ nifty\ bits\ of\n\[introspection\]\ -\ for\ example,\ if\ `\[info\ body\]`\ returned\ a\ pure\ list\ of\ lists\n\[introspection\]\ -\ for\ example,\ if\ \[info\ body\]\ returned\ a\ pure\ list-of-lists\nwhole\ program\ becomes\ a\ list\ of\ lists.\n\nThe\ problem\ is\ how\ to\ signal\ to\ `eval`\ (or\ `\[uplevel\]`,\ `\[namespace\]`,\ `\[bind\]`,\ ...)\ that\ it\nThe\ problem\ is\ how\ to\ signal\ to\ eval\ (or\ uplevel,\ namespace,\ bind,\ ...)\ that\ it\nis\ a\ list\ of\ lists\ rather\ than\ just\ a\ list.\ \ Could\ eval\ determine\ if\ its\ input\nprogn?\n\nAnother\ place\ this\ seems\ like\ it\ could\ be\ useful:\ I\ have\ a\ \[pkgIndex.tcl\]\ file\ with\nAnother\ place\ this\ seems\ like\ it\ could\ be\ useful:\ I\ have\ a\ pkgIndex\ file\ with\n\npackage\ ifneeded\ tls\ 1.4\ \[\npackage\ ifneeded\ tls\ 1.4\ \"\[list\ load\ \[file\ join\ \$dir\ libtls1.4.so\]\]\;\[list\ source\ \[file\ join\ \$dir\ tls.tcl\]\]\"\n\nwhere\ most\ of\ the\ lines\ are\ like\n\n======\npackage\ ifneeded\ tclperl\ 2.3\ \[list\ load\ \[file\ join\ \$dir\ tclperl.so\]\]\n======\n\nsince\ they\ only\ need\ one\ command\;\ but\ the\ tls\ line\ needs\ two\ commands.\ \ So\ why\ can't\ it\ be\n\n======\npackage\ ifneeded\ tls\ 1.4\ \[list\ \[\npackage\ ifneeded\ tls\ 1.4\ \[list\ \[list\ load\ \[file\ join\ \$dir\ libtls1.4.so\]\]\ \[list\ source\ \[file\ join\ \$dir\ tls.tcl\]\]\]\n\n\n\n\n\[RS\]\ 2004-02-06:\ As\ usual\ in\ Tcl,\ functionality\ you\ miss\ you\ can\ easy\ roll\nyourself.\ I\ needed\ a\ progn-like\ list\ eval\ in\ \[RPN\ again\],\ and\ did\ it\ similar\ to\nthis:\n\n======\nproc\ leval\ args\ \{\n\ \ \ \ foreach\ arg\ \$args\ \{\n\ \ \ \ \ \ \ \ set\ res\ \[uplevel\ 1\ \$arg\]\n\ \ \ \ \}\n\ \ \ \ set\ res\ \;#\ return\ last\ (\"n-th\")\ result,\ as\ Tcl\ evaluation\ does\n\}\n======\n\n\n\n**\ eval\ versus\ bytecode\ **\n**\ `eval`\ versus\ bytecode\ **\n\[AMG\]:\ It\ appears\ `\[\[eval\]\]`'ed\ code\ does\ not\ get\ \[bytecode\]-compiled,\ even\nwhen\ \[\[eval\]\]\ is\ passed\ a\ single\ brace-quoted\ argument.\ \ The\ same\ is\ true\ for\n`\[\[\[uplevel\]\ 0\]`\ and\ `\[\[\[time\]\]`.\ \ `\[\[\[catch\]\]`\ and\ `\[\[\[if\]\ \{1\}\]\]`\ seem\ to\ be\n\"argument\",\ rather\ a\ single\ command\ line\ pre-chewed\ into\ an\ objv\ list.\nBytecoding\ cannot\ take\ place\ when\ the\ argument\ is\ the\ product\ of\ `\[list\]`,\nBytecoding\ cannot\ take\ place\ when\ the\ argument\ is\ the\ product\ of\ `\[\[\[list\]\]`,\n\n======\nproc\ a\ \{\}\ \{eval\ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ b\ \{\}\ \{uplevel\ 0\ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ c\ \{\}\ \{time\ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ d\ \{\}\ \{catch\ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ e\ \{\}\ \{if\ \{1\}\ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ f\ \{\}\ \{\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ g\ \{\}\ \{eval\ \ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ h\ \{\}\ \{uplevel\ 0\ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ i\ \{\}\ \{time\ \ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ j\ \{\}\ \{catch\ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ k\ \{\}\ \{if\ \{1\}\ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ l\ \{\}\ \{\ \ \ \ \ \ \ \{*\}\[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ m\ \{\}\ \{try\ \ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\na\;b\;c\;d\;e\;f\;g\;h\;i\;j\;k\;l\;m\ntime\ a\ 10\ \ \ \ \;#\ \ 80723.8\ microseconds\ per\ iteration\ -\ slow\ntime\ b\ 10\ \ \ \ \;#\ \ 65380.2\ microseconds\ per\ iteration\ -\ slow\ntime\ c\ 10\ \ \ \ \;#\ \ 66024.8\ microseconds\ per\ iteration\ -\ slow\ntime\ d\ 100\ \ \ \;#\ \ 18888.3\ microseconds\ per\ iteration\ -\ fast\ntime\ e\ 100\ \ \ \;#\ \ 18779.3\ microseconds\ per\ iteration\ -\ fast\ntime\ f\ 100\ \ \ \;#\ \ 19375.2\ microseconds\ per\ iteration\ -\ fast\ntime\ g\ 10\ \ \ \ \;#\ 319111.5\ microseconds\ per\ iteration\ -\ very\ slow\ntime\ h\ 10\ \ \ \ \;#\ 342878.4\ microseconds\ per\ iteration\ -\ very\ slow\ntime\ i\ 10\ \ \ \ \;#\ 322279.2\ microseconds\ per\ iteration\ -\ very\ slow\ntime\ j\ 10\ \ \ \ \;#\ 316939.0\ microseconds\ per\ iteration\ -\ very\ slow\ntime\ k\ 10\ \ \ \ \;#\ 321865.5\ microseconds\ per\ iteration\ -\ very\ slow\ntime\ l\ 10\ \ \ \ \;#\ 344009.5\ microseconds\ per\ iteration\ -\ very\ slow\ntime\ m\ 100\ \ \ \;#\ \ 19503.0\ microseconds\ per\ iteration\ -\ fast\n======\n\nI\ want\ single-argument\ `eval`\ functionality\ in\ my\ code,\ but\ I\ also\ want\nI\ want\ single-argument\ `\[\[\[eval\]\]`\ functionality\ in\ my\ code,\ but\ I\ also\ want\nbytecoding.\ \ `\[\[\[catch\]\]`\ has\ the\ undesirable\ side\ effect\ of\ hiding\ errors,\ so\nI\ guess\ I\ have\ to\ use\ `\[\[\[if\]\ \{1\}\]`\ which\ is\ a\ really\ weird\ idiom.\ \ Does\ anyone\n\n\[AMG\]:\ I\ reran\ the\ tests\ and\ got\ better\ numbers.\ \ The\ current\ version\ of\ Tcl\nmust\ be\ faster\ than\ whatever\ I\ used\ when\ I\ first\ did\ this\ benchmark\ (I'm\ using\nthe\ same\ computer).\ \ Look\ in\ the\ page\ history\ to\ see\ the\ comparison.\ \ More\nimportantly,\ I\ think\ I\ found\ a\ bytecoded\ `eval`:\ single-argument\ `\[try\]`.\nimportantly,\ I\ think\ I\ found\ a\ bytecoded\ \[\[eval\]\]:\ single-argument\ \[\[\[try\]\]\].\nmethods.\ \ It's\ considerably\ less\ weird\ than\ `\[if\]\ 1`,\ and\ it\ doesn't\ hide\nmethods.\ \ It's\ considerably\ less\ weird\ than\ \[\[if\ \{1\}\]\],\ and\ it\ doesn't\ hide\n\n\[DKF\]:\ We've\ been\ focusing\ a\ bit\ more\ on\ improving\ the\ most\ cripplingly-slow\ncases,\ but\ three\ execution\ modes\ still\ exist\ that\ have\ fundamentally\ different\nspeeds.\ There's\ compilation\ to\ bytecode-with-local-var-table\ (which\ is\ the\nfastest\;\ the\ speed\ comes\ from\ being\ able\ to\ compile\ in\ indexes\ into\ the\ LVT\ninto\ the\ generated\ bytecode,\ which\ this\ test\ is\ particularly\ sensitive\ to),\nthere's\ compilation\ to\ bytecode-without-LVT\ (slower\;\ variables\ have\ to\ be\nlooked\ up\ each\ time\ they're\ accessed),\ and\ there's\ interpreting\ (slowest\ by\nfar).\ There's\ not\ much\ point\ in\ doing\ a\ lot\ of\ comparison\ between\ the\ three\;\nthey\ all\ exist\ for\ a\ reason.\ (We\ could\ make\ straight\ `eval`/`\[uplevel\]\nthey\ all\ exist\ for\ a\ reason.\ (We\ could\ make\ straight\ '''eval'''/'''\[uplevel\]\n0'''\ of\ constant\ arguments\ work\ at\ full\ speed,\ but\ we\ see\ no\ reason\ to\ bother\ngiven\ how\ rare\ they\ are\ in\ real\ code,\ and\ it's\ better\ that\ \[time\]\ is\ kept\nto\ get\ by\ using\ `\[::tcl::unsupported::disassemble\]`\ to\ look\ at\ the\ bytecode\ to\ see\nto\ get\ by\ using\ \[tcl::unsupported::disassemble\]\ to\ look\ at\ the\ bytecode\ to\ see\ndone\ by\ just\ building\ arguments\ and\ invoking\ “cnormal”\ commands.\ndone\ by\ just\ building\ arguments\ and\ invoking\ “normal”\ commands.\n\[Twylite\]\ 2012-08-24:\ \ I've\ been\ optimising\ some\ control\ constructs\ and\ was\ntrying\ to\ understand\ the\ performance\ of\ various\ combinations\ of\ uplevel,\ntailcall,\ catch\ and\ try.\ \ Along\ the\ way\ I\ found\ \[AMG\]'s\ performance\ figures,\nand\ have\ updated\ them\ with\ some\ new\ ones:\n\n======\n#\ Fast\ (prefix\ f)\nproc\ f_baseline\ \ \ \ \ \ \ \{\}\ \{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\ \}\nproc\ f_catch\ \ \ \ \ \ \ \ \ \ \{\}\ \{catch\ \ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ f_catch\ \ \ \ \ \ \ \ \ \ \{\}\ \{catch\ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ f_if_1\ \ \ \ \ \ \ \ \ \ \ \{\}\ \{if\ \{1\}\ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ f_expand\ \ \ \ \ \ \ \ \ \{\}\ \{\ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ f_try\ \ \ \ \ \ \ \ \ \ \ \ \{\}\ \{try\ \ \ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ f_time_apply\ \ \ \ \ \{\}\ \{time\ \{apply\ \{\{\}\ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\}\}\n#\ Medium\ (prefix\ m)\ \ \ \ \ \ \ \ \ \ \ \ \ \nproc\ m_eval\ \ \ \ \ \ \ \ \ \ \ \{\}\ \{eval\ \ \ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ m_eval\ \ \ \ \ \ \ \ \ \ \ \{\}\ \{eval\ \ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ m_uplevel_0\ \ \ \ \ \ \{\}\ \{uplevel\ 0\ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ m_time\ \ \ \ \ \ \ \ \ \ \ \{\}\ \{time\ \ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ m_tailcall_try\ \ \ \{\}\ \{tailcall\ \ \ \ try\ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ m_catch_uplvl_1\ \ \{\}\ \{\ \ \ \ \ \ \ set\ body\ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\ \;\ catch\ \{\ uplevel\ 1\ \$body\ \}\ \}\ \ \nproc\ m_uplvl_1_catch\ \ \{\}\ \{\ \ \ \ \ \ \ set\ body\ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\ \;\ uplevel\ 1\ \[list\ catch\ \$body\]\ \}\ \ \n#\ Slow\ (prefix\ s)\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \nproc\ s_eval_list\ \ \ \ \ \ \{\}\ \{eval\ \ \ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ s_uplevel_0_list\ \{\}\ \{uplevel\ 0\ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ s_time_list\ \ \ \ \ \ \{\}\ \{time\ \ \ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ s_catch_list\ \ \ \ \ \{\}\ \{catch\ \ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ s_if_1_list\ \ \ \ \ \ \{\}\ \{if\ 1\ \ \ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ s_if_1_list\ \ \ \ \ \ \{\}\ \{if\ \{1\}\ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ s_tailcall\ \ \ \ \ \ \ \{\}\ \{tailcall\ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\ \}\n\nif\ 0\ \{\nif\ \{0\}\ \{\n\ \ set\ REPS\ \{f\ 10\ m\ 40\ s\ 100\}\ \;#\ reps\ by\ prefix\n\ \ set\ cmds\ \{f_baseline\ f_catch\ f_if_1\ f_expand\ f_try\ f_time_apply\ \n\ \ \ \ m_eval\ m_uplevel_0\ m_time\ m_tailcall_try\ m_catch_uplvl_1\ m_uplvl_1_catch\ \n\ \ \ \ s_eval_list\ s_uplevel_0_list\ s_time_list\ s_catch_list\ s_if_1_list\ \n\ \ \ \ s_expand_list\ s_tailcall\}\n\ \ \n\ \ foreach\ cmd\ \$cmds\ \{\ \$cmd\ \}\ \;#\ compile\n\ \ set\ cmdrepstimes\ \{\}\ \;\ foreach\ cmd\ \$cmds\ \{\ \;#\ time\n\ \ \ \ set\ reps\ \[dict\ get\ \$::REPS\ \[string\ index\ \$cmd\ 0\]\]\ \n\ \ \ \ lappend\ cmdrepstimes\ \[lindex\ \[time\ \$cmd\ \$reps\]\ 0\]\ \$cmd\ \$reps\ \n\ \ \}\n\ \ \n\ \ set\ mintime\ \[::tcl::mathfunc::min\ \{*\}\$times\]\n\ \ foreach\ \{t\ cmd\ reps\}\ \[lsort\ -real\ -stride\ 3\ \$cmdrepstimes\]\ \{\n\ \ \ \ puts\ \[format\ \"time\ %-16s\ \$reps\\t\;#\ %9.1f\ microseconds\ per\ iteration,\ factor\ %5.2f\"\ \\\n\ \ \ \ \ \ \$cmd\ \$t\ \[expr\ \{\ \$t\ /\ \$mintime\ \}\]\ \]\ \n\ \ \}\n\ntime\ f_time_apply\ \ \ \ \ 10\ \ \ \ \ \ \ \ \;#\ \ \ \ 4625.8\ microseconds\ per\ iteration,\ factor\ \ 1.00\ntime\ f_if_1\ \ \ \ \ \ \ \ \ \ \ 10\ \ \ \ \ \ \ \ \;#\ \ \ \ 4641.8\ microseconds\ per\ iteration,\ factor\ \ 1.00\ntime\ f_expand\ \ \ \ \ \ \ \ \ 10\ \ \ \ \ \ \ \ \;#\ \ \ \ 4645.0\ microseconds\ per\ iteration,\ factor\ \ 1.00\ntime\ f_catch\ \ \ \ \ \ \ \ \ \ 10\ \ \ \ \ \ \ \ \;#\ \ \ \ 4651.3\ microseconds\ per\ iteration,\ factor\ \ 1.00\ntime\ f_baseline\ \ \ \ \ \ \ 10\ \ \ \ \ \ \ \ \;#\ \ \ \ 4658.5\ microseconds\ per\ iteration,\ factor\ \ 1.01\ntime\ f_try\ \ \ \ \ \ \ \ \ \ \ \ 10\ \ \ \ \ \ \ \ \;#\ \ \ \ 4735.9\ microseconds\ per\ iteration,\ factor\ \ 1.02\ntime\ m_eval\ \ \ \ \ \ \ \ \ \ \ 40\ \ \ \ \ \ \ \ \;#\ \ \ 18454.3\ microseconds\ per\ iteration,\ factor\ \ 3.98\ntime\ m_uplevel_0\ \ \ \ \ \ 40\ \ \ \ \ \ \ \ \;#\ \ \ 18738.3\ microseconds\ per\ iteration,\ factor\ \ 4.04\ntime\ m_time\ \ \ \ \ \ \ \ \ \ \ 40\ \ \ \ \ \ \ \ \;#\ \ \ 19176.8\ microseconds\ per\ iteration,\ factor\ \ 4.14\ntime\ m_uplvl_1_catch\ \ 40\ \ \ \ \ \ \ \ \;#\ \ \ 21501.1\ microseconds\ per\ iteration,\ factor\ \ 4.64\ntime\ m_catch_uplvl_1\ \ 40\ \ \ \ \ \ \ \ \;#\ \ \ 21603.1\ microseconds\ per\ iteration,\ factor\ \ 4.66\ntime\ m_tailcall_try\ \ \ 40\ \ \ \ \ \ \ \ \;#\ \ \ 21698.4\ microseconds\ per\ iteration,\ factor\ \ 4.68\ntime\ s_uplevel_0_list\ 100\ \ \ \ \ \ \ \;#\ \ \ 84963.3\ microseconds\ per\ iteration,\ factor\ 18.34\ntime\ s_eval_list\ \ \ \ \ \ 100\ \ \ \ \ \ \ \;#\ \ \ 85519.3\ microseconds\ per\ iteration,\ factor\ 18.46\ntime\ s_catch_list\ \ \ \ \ 100\ \ \ \ \ \ \ \;#\ \ \ 85919.9\ microseconds\ per\ iteration,\ factor\ 18.54\ntime\ s_time_list\ \ \ \ \ \ 100\ \ \ \ \ \ \ \;#\ \ \ 85944.2\ microseconds\ per\ iteration,\ factor\ 18.55\ntime\ s_if_1_list\ \ \ \ \ \ 100\ \ \ \ \ \ \ \;#\ \ \ 87269.0\ microseconds\ per\ iteration,\ factor\ 18.84\ntime\ s_expand_list\ \ \ \ 100\ \ \ \ \ \ \ \;#\ \ \ 93096.9\ microseconds\ per\ iteration,\ factor\ 20.09\ntime\ s_tailcall\ \ \ \ \ \ \ 100\ \ \ \ \ \ \ \;#\ \ \ 94473.5\ microseconds\ per\ iteration,\ factor\ 20.39\n======\n\n\n regexp2} CALL {my render eval '''\[http://www.tcl.tk/man/tcl/TclCmd/eval.htm%|%eval\]''',\ a\ \[Tcl\ Commands%|%built-in\]\ Tcl\ \[command\],\ interprets\ its\ arguments\ as\ a\ \[script\],\nwhich\ it\ then\ evaluates.\n\n\n\n**\ Synopsis\ **\n\n\ \ \ \ :\ \ \ '''eval'''\ ''arg''\ ?''arg\ ...''?\ \ \n\n\n\n\n\n\ \ \ \[Injection\ Attack\]:\ \ \ \n\ \ \ \[introspection\]:\ \ \ \n\ \ \ \[Introspection\]:\ \ \ \n\ \ \ \[Many\ ways\ to\ eval\]:\ \ \ \n\ \ \ \[Many\ Ways\ to\ eval\]:\ \ \ \n\n\ \ \ \[try\]:\ \ \ can\ be\ used\ as\ \[bytecode%|%byte-coded\]\ alternative\ to\ `eval`\n\n\n\n\ \ \ \[http://www.tcl.tk/man/tcl/TclCmd/eval.htm%|%official\ reference\]:\ \ \ \n\n\n\n**\ Description\ **\n**\ Usage\ **\n\n`\[\[\[if\]\ 1\ ...\]`,\ which\ is\ byte-compiled,\ is\ an\ efficient\ replacement\ for\n`\[\[\[eval\]\]`\ in\ all\ cases.\ \ Thus,\ modern\ Tcl\ code\ has\ zero\ use\ for\ `\[\[eval\]`.\n\nTo\ avoid\ the\ caveats\ of\ `\[\[eval\]`\ the\ rule\ of\ thumb\ is\ to\ pass\ only\ one\nargument\ to\ `\[\[eval\]`.\ \ Passing\ a\ single\ script,\ rather\ than\ relying\ on\nimplicit\ concatenation\ helps\ to\ avoid\ dumb\ mistakes\ such\ as\ passing\ a\ string\nwhich\ contains\ newlines.\n\n\n\n\n'''`eval`'''\ concatenates\ its\ arguments\ in\ the\ same\ fashion\ as\n'''`\[\[eval\]`'''\ concatenates\ its\ arguments\ in\ the\ same\ fashion\ as\n`\[\[\[concat\]\]`,\ and\ hands\ them\ to\ the\ interpreter\ to\ be\ evaluated\ as\ a\ Tcl\nscript\ in\ the\ scope\ of\ the\ caller\ of\ \[\[`\[eval\]`\].\ \ It\ then\ returns\ the\ result\n\n`eval`\ is\ an\ old,\ old\ command\ that's\ been\ in\ \[Tcl\]\ from\ the\ beginning.\n`\[\[\[eval\]\]`\ is\ an\ old,\ old\ command,\ that's\ been\ in\ \[Tcl\]\ from\ the\ beginning.\n`eval`\ is\ useful\ when\ one\ wishes\ to\ generate\ a\ script\ and\ then\ interpret\ it.\n`\[\[eval\]`\ is\ useful\ when\ one\ wishes\ to\ generate\ a\ script\ and\ then\ interpret\ it.\nIn\ modern\ Tcl,\ `\[\[eval\]`\ is\ merely\ an\ abbreviation\ for\ `\[\[\[uplevel\]\ 0\]`.\ \ This\n'''self-modifying\ programs''',\ and\ related\ esoterica.\n\"self-modifying\ programs\",\ and\ related\ esoterica.\n`\[if\]\ 1\ ...`,\ which\ may\ be\ \[bytecode%|%byte-compiled\],\ is\ an\ efficient\nBecause\ the\ script\ is\ evaluated\ in\ the\ scope\ of\ the\ caller\ of\ \[\[`\[eval\]`\]\ a\nterminating\ command\ like\ \[\[`\[return\]`\]\ will\ cause\ the\ caller\ of\ \[\[`\[eval\]`\]\ to\n\n`eval`\ is\ used\ by\ \ all\ the\ commands\ --\ `\[bind\]`,\ everything\ with\n`\[\[eval\]`\ is\ used\ by\ \ all\ the\ commands\ --\ `\[\[\[bind\]\]`,\ everything\ with\n\nWhen\ using\ `eval`,\ it\ is\ very\ easy\ to\ leave\ holes\ which\ can\ be\ exploited\ to\nWhen\ using\ `\[\[eval\]`,\ it\ is\ very\ easy\ to\ leave\ holes\ which\ can\ be\ exploited\ to\ninject\ malicious\ code,\ so\ it\ is\ best\ to\ exercise\ extreme\ care\ with\ it\ until\ one\n\n`eval`\ can\ often\ be\ avoided,\ particularly\ with\ more\ modern\ recent\ versions\ of\n`\[\[eval\]`\ can\ often\ be\ avoided,\ particulary\ with\ more\ modern\ recent\ versions\ of\n\n\n\n**\ Eval\ and\ \[double\ substitution\]\ **\n**\ Eval\ and\ \[double\ subsitition\]\ **\n`eval`\ is\ one\ of\ the\ Tcl\ constructs\ that\ causes\ the\ Tcl\ interpreter\ to\n`\[\[\[eval\]\]`\ is\ one\ of\ the\ Tcl\ constructs\ that\ causes\ the\ Tcl\ interpreter\ to\nscan\ over\ its\ arguments\ another\ time\ and\ evalutate\ what\ it\ scans.\nGiven\ the\ following\ assignment,\n\n======\nset\ b\ \{the\ total\ is\ \$20\}\nset\ b\ \"the\ total\ is\ \$20\"\n\neach\ of\ the\ following\ commands\ returns\ a\ is\ different\ result:\neach\ of\ the\ following\ commands\ is\ subtly\ different:\n\nset\ a\ \$b\neval\ \{set\ a\ \$b\}\neval\ \"set\ a\ \$b\"\neval\ \[list\ set\ a\ \$b\]\n======\n\nConsider\ the\ first\ one,\n\n======\nset\ a\ \$b\n======\n\nPrior\ to\ invoking\ `\[set\]`,\ Tcl\ performs\ its\ substitutions,\ so\ the\ command\nPrior\ to\ invoking\ `\[\[\[set\]\]`,\ Tcl\ performs\ its\ substitutions,\ so\ the\ command\n\n======\n\ \ \ `set\ a\ \{the\ total\ is\ \$20\}`:\n`\[set\]`\ receives\ the\ arguments\ `a`,\ and\ `the\ total\ is\ \$20`,\ does\ not\ perform\n`\[\[\[set\]\]`\ receives\ the\ arguments\ `a`,\ and\ `the\ total\ is\ \$20`,\ does\ not\ perform\n`the\ total\ is\ \$20`.\n\nIn\ the\ second\ one,\ \n\n======\neval\ \{set\ a\ \$b\}\n======\n\nTcl\ does\ not\ perform\ any\ substitutions\ on\ the\ value\ in\ curly\ brackets,\ so\ the\nTcl\ does\ not\ perform\ an\ substitutions\ on\ the\ value\ in\ curly\ brackes,\ so\ the\ncommand\ remains\ unchanged.\ \ `\[\[\[eval\]\]`\ receives\ one\ argument,\n======\n\ \ \ `set\ a\ \$b`:\ \ \ \nwhich\ it\ then\ hands\ back\ to\ the\ interpreter.\ \ This\ time\ the\ interpreter\ sees\n`set\ a\ \$b`,\ which\ becomes:\n`set\ a\ \$b`,\ which\ becomes\n======\n\ \ \ `set\ a\ \{the\ total\ is\ \$20\}`:\ \ \ \nso\ the\ value\ of\ `\$a`\ becomes\ `the\ total\ is\ \$20`.\n,\ so\ the\ value\ of\ `\$a`\ becomes\ `the\ total\ is\ \$20`.\nIn\ the\ third\ example,\ \n\n======\neval\ \"set\ a\ \$b\"\n======\n\nTcl\ changes\ the\ command\ to\n\n======\n\ \ \ `eval\ \{set\ a\ the\ total\ is\ \$20\}`:\ \ \ \n`eval`\ receives\ the\ argument\n`\[\[\[eval\]\]`\ receives\ the\ argument\n======\n\ \ \ `set\ a\ Hello\ There`:\ \ \ \nand\ hands\ it\ to\ the\ interpreter\ for\ evaluation.\ \ This\ time,\ the\ interpreter\nsees\n\n======\n\ \ \ `set\ a\ the\ total\ is\ \$20`:\ \ \ \nfails\ to\ find\ the\ variable\ `\$20`\ and\ raises\ an\ error.\ \ If\ there\ had\ been\ no\n,\ fails\ to\ find\ the\ variable\ `\$20`,\ and\ raises\ an\ error.\ \ If\ there\ had\ been\ no\nvariable\ error,\ the\ interpreter\ would\ have\ invoked\ `\[\[\[set\]\]`\ with\ too\ many\narguments,\ causing\ `\[\[\[set\]\]\]`\ to\ raise\ an\ error.\n======\neval\ \[list\ set\ a\ \$b\]\n======\n\nTcl\ changes\ the\ command\ to\ `eval\ \{set\ a\ \{the\ total\ is\ \$20\}\}`,\ \ `\[set\]`\nTcl\ changes\ the\ command\ to\ `eval\ \{set\ a\ \{the\ total\ is\ \$20\}\}`,\ \ `\[\[\[set\]\]`\n`the\ total\ is\ \$20`.\n\n\n\nSee\ \[double\ substitution\]\ for\ the\ details\ of\ why\ it\ can\ be\ dangerous.\n\n\n**\ Is\ `eval`\ Evil?\ **\n**\ Is\ `\[\[eval\]`\ Evil?\ **\nShort\ answer:\ No.\ \ Like\ many\ commands\ in\ Tcl,\ `eval`\ can\ lead\ to\ \[double\nShort\ answer:\ No.\ \ Like\ many\ commands\ in\ Tcl,\ `\[\[eval\]`\ can\ lead\ to\ \[double\nskilled\ Tcl\ programmer\ knows\ how\ to\ wield\ \[double\ substitution\].\n\nHistorically,\ `eval`\ was\ often\ used\ with\ exec,\ to\ flatten\ lists,\ allowing\nHistorically,\ `\[\[\[eval\]\]`\ was\ often\ used\ with\ exec,\ to\ flatten\ lists,\ allowing\na\ single\ list\ to\ provide\ multiple\ arguments\ to\ a\ command:\ \n======\n#warning:\ no-longer\ recommended\neval\ exec\ grep\ foo\ \$filelist\n======\n\nbecause\ otherwise\ ''grep''\ would\ receive\ filelist\ as\ one\ long\ filename\ with\ embedded\ blanks.\nIn\ modern\ Tcl,\ the\ following\ is\ preferred:\nIn\ modern\ Tcl,\ the\ following\ is\ preferred\ for\ reasons\ of\ efficiency\ and\ safety:\nexec\ grep\ foo\ \{*\}\$filelist\n======\n\nOr,\ if\ you\ want\ to\ append\ one\ list's\ elements\ to\ another,\ and\ you're\ willing\ to\ assume\ that\ the\ variable\ containing\ the\ new\ elements\ doesn't\ embed\ any\ unquoted\ semicolons\ or\ newlines:\nembedded\ blanks.\ Or,\ if\ you\ want\ to\ append\ one\ list's\ elements\ to\ another:\n======\neval\ lappend\ thislist\ \$thatlist\nset\ thislist\ \[concat\ \$thislist\ \$thatlist\]\ \;#\ can\ also\ be\ done\ as\n======\n\nThough\ the\ following\ two\ options\ are\ safer\ and\ faster:\nstring)\ and\ finally\ calling\n\n======\neval\ \$script\n======\n\nWhen\ the\ script\ contains\ only\ one\ command,\ \[argument\ expansion\]\ is\ preferred:\n\n======\n\{*\}\$cmd\n======\n\n**\ Expanding\ Lists\ with\ `eval`\ **\n**\ Expanding\ Lists\ with\ `\[\[eval\]`\ **\nPrior\ to\ Tcl\ version\ 8.5,\ one\ use\ case\ for\ `eval`\ was\ to\ expand\ lists.\nPrior\ to\ Tcl\ version\ 8.5,\ one\ use\ case\ for\ `\[\[eval\]`\ was\ to\ expand\ lists.\nThere\ is\ no\ longer\ any\ reason\ to\ do\ this.\ \ Use\ `\[\{*\}\]`\ instead.\nSee\ \[Argument\ expansion\].\n\n----\nInstead\ of:\n\n\n======\n#warning:\ not\ recommended\neval\ pack\ \[winfo\ children\ .\]\n======\n\nuse:\n\n======\npack\ \{*\}\[winfo\ children\ .\]\n======\n\n----\n\nAnd\ instead\ of:\n\n======\n#warning:\ this\ is\ not\ recommended\nset\ filepath\ \[list\ path\ to\ the\ file\]\neval\ file\ join\ \$filepath\n======\n\nuse:\n\n======\nset\ filepath\ \[list\ path\ to\ the\ file\]\nfile\ join\ \{*\}\$filepath\n======\n\n----\nAnother\ similar\ example\n\n\n======\n#the\ old\ (bad)\ way\nset\ f\ \[glob\ *.tcl\]\neval\ \[linsert\ \$f\ 0\ exec\ lp\]\n======\n\n======\n#the\ shiny\ new\ way\nexec\ lp\ \{*\}\$f\n======\n\n\n***\ Historical\ ***\n\nThe\ following\ describes\ the\ situation\ before\ the\ advent\ of\ \[\{*\}\]:\n\nNaive\ code\ might\ look\ like\ this\ (an\ actual\ example\ from\ BWidget's\nentry.tcl:97):\n\n======\n#warning:\ bad\ code\ ahead!\neval\ entry\ \$path\ \$maps(:cmd)\n======\n\nAn\ unsuccessful\ attempt\ to\ fix\ the\ problem:\nAn\ unsuccesful\ attempt\ to\ fix\ the\ problem:\n======\n#warning:\ bad\ code\ ahead!\neval\ entry\ \[list\ \$path\]\ \$maps(:cmd)\n======\n\nBut\ `\$maps(:cmd)`\ might\ be\ a\ string\ with\ newlines:\n\n======\nset\ maps(:cmd)\ \{\n\ \ \ \ -opt1\ val1\n\ \ \ \ -opt2\ val2\n\}\n======\n\nIt's\ necessary\ to\ first\ convert\ `\$maps(:cmd)`\ to\ a\ proper\ list\ using\ one\ of\ the\nlist\ commands:\n\n======\neval\ \[linsert\ \$maps(:cmd)\ 0\ entry\ \$path\]\n======\n\n***\ See\ Also\ ***\n\n\ \ \ \[http://code.activestate.com/lists/tcl-core/414/%|%RE:\ TCLCORE\ Re:\ CFV:\ TIPs\ #156\ and\ #157\],\ \[Jeff\ Hobbs\],\ \[Tcl\ Core\ Team%|%tcl-core\ mailing\ list\],\ 2003-10-12:\ \ \ \[AMG\]:\ Text\ repeated\ below,\ please\ read\ it\ until\ you\ understand\ what\ trouble\ \[\[eval\]\]\ buys\ you\ and\ how\ helpful\ \[\{*\}\]\ is.\n\ \ \ \[http://code.activestate.com/lists/tcl-core/414/%|%RE:\ \[TCLCORE\]\ Re:\ CFV:\ TIPs\ #156\ and\ #157\]\ ,\[Jeffrey\ Hobbs%|%Jeff\ Hobbs\]\ ,\[Tcl\ Core\ Team%|%tcl-core\ mailing\ list\]\ ,2003-10-12:\ \ \ \n\ \ \ \[http://web.archive.org/web/20060325121839/http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/1748289%|%TCLCORE\ TIP\ #144:\ Argument\ Expansion\ Syntax\],\ \[Jeff\ Hobbs\],\ \[Tcl\ Core\ Team%|%tcl-core\ mailing\ list\],\ 2003-07-26:\ \ \ \n\ \ \ \[http://web.archive.org/web/20060325121839/http://aspn.activestate.com/ASPN/Mail/Message/tcl-core/1748289%|%TCLCORE\ TIP\ #144:\ Argument\ Expansion\ Syntax\]\ ,\[Jeffrey\ Hobbs%|%Jeff\ Hobbs\]\ ,\[Tcl\ Core\ Team%|%tcl-core\ mailing\ list\]\ ,2003-07-26:\ \ \ \n\n\ \ \ \[http://groups.google.com/group/comp.lang.tcl/browse_thread/thread/c3d6651005e12629/a9dc3e05d95b0f12?hl=en&ie=UTF-8&q=argument+expansion+apply+variadic+group:comp.lang.tcl*#%|%eval\ is\ evil\ (for\ spreading\ list-arguments)\]\ ,\[comp.lang.tcl\]\ ,2003-03-11:\ \ \ \n****\ Re:\ CFV:\ TIPs\ #156\ and\ #157\ ****\n\n***\ Re:\ CFV:\ TIPs\ #156\ and\ #157\ **\n\n\[AMG\]:\n======none\n>\ miguel\ sofer\ <mig@ut...>\ writes:\n>\ >\ In\ tcllib,\ every\ effort\ is\ done\ to\ provide\ code\ that\ runs\ \n>\ >\ conditionally\ on\ the\ tcl\ version\ and\ provides\ the\ new\ functionality\ \n>\ >\ toold\ interpreters.\n>\ \n>\ But\ the\ TIP\ doesn't\ specify\ any\ new\ functionality.\ \ It\ only\ \n>\ specifies\ a\ new\ syntax\ for\ functionality\ that\ we\ already\ \n>\ have.\ \ I\ don't\ see\ a\ need\ to\ complicate\ code\ by\ providing\ two\ \n>\ implementations,\ when\ one\ of\ the\ implementations\ (the\ old\ \n>\ one)\ works\ on\ all\ versions\ of\ Tcl\ and\ has\ no\ functional\ drawbacks.\n\nAlright,\ this\ is\ where\ I\ step\ in\ to\ note\ how\ important\ this\ change\ is,\nand\ to\ correct\ everyone's\ completely\ false\ assumption\ that\ the\ existing\neval\ hell\ has\ no\ functional\ drawbacks.\ \ dgp\ asked\ me\ to\ post\ these\npoints\ that\ I\ made\ at\ Tcl2003\ earlier,\ but\ I\ didn't\ think\ it\ necessary.\nIt\ obviously\ is.\ \ It\ goes\ a\ little\ something\ like\ this:\n\nRaise\ your\ hand\ if\ you\ think\ this\ is\ correct:\n\n\ \ \ \ \ \ \ \ eval\ entry\ \$path\ \$args\n\nEveryone\ raising\ their\ hand\ please\ sit\ down.\ \ You\ are\ wrong.\ \ The\ \$path\narg\ will\ be\ split\ apart\ as\ well,\ which\ is\ bad\ when\ using\ this\ in\ low\nlevel\ code,\ like\ megawidgets\ or\ the\ like,\ where\ it\ must\ be\ handled\ncorrectly.\ \ After\ all,\ widgets\ with\ spaces\ in\ the\ names\ is\ 100%\ valid.\n\nOK,\ so\ we\ know\ the\ fix,\ right?\n\n\ \ \ \ \ \ \ \ eval\ entry\ \[list\ \$path\]\ \$args\n\nAh,\ that's\ better\ ...\ but\ something\ is\ not\ right.\ \ Hmmm\ ...\ oh,\ it\ is\ninefficient!\ \ The\ mix\ of\ list\ and\ string\ args\ will\ walk\ the\ wrong\ path\nfor\ optimization\ (this\ isn't\ important\ to\ everybody,\ but\ good\ low\ level\ncode\ writers\ should\ be\ sensitive\ to\ this).\ \ OK,\ so\ that\ means\ this\ is\nthe\ best,\ right?\n\n\ \ \ \ \ \ \ \ eval\ \[list\ entry\ \$path\]\ \$args\n\nNow\ I\ feel\ better.\ \ What,\ that's\ not\ right?\ \ If\ string\ args\ is\ actually\na\ multiline\ string,\ it\ won't\ work\ as\ expected.\ \ Try\ it\ with:\n\n\ \ \ \ \ \ \ \ set\ args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ -opt1\ val1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ -opt2\ val2\n\ \ \ \ \ \ \ \ \}\n\nand\ unfortunately\ that\ isn't\ theoretical.\ \ I've\ seen\ code\ that\ uses\ a\n\$defaultArgs\ set\ up\ like\ that\ before\ regular\ args\ to\ handle\ defaults.\n\nUgh\ ...\ what\ are\ we\ left\ with?\ \ This:\n\n\ \ \ \ \ \ \ \ eval\ \[linsert\ \$args\ 0\ entry\ \$path\]\n\nOnly\ the\ final\ version\ is\ 100%\ correct,\ guaranteed\ not\ to\ blow\ when\ you\nleast\ want\ it\ to.\n\nSo\ we\ get\ back\ to\ the\ original\ point\ ...\ eval\ itself\ may\ not\ be\nfunctionally\ flawed,\ but\ 99%\ of\ eval\ uses\ are.\ \ In\ fact\ I\ don't\ always\nuse\ the\ final\ solution\ in\ code\ because\ it\ can\ get\ so\ unwieldly,\ but\ now\nlet\ me\ focus\ on\ tcllib,\ which\ was\ mentioned.\ \ First\ let\ me\ say\ that\ my\nfavored\ solution\ is\ so\ much\ easier\ to\ use,\ has\ a\ minimal\ ugly\ factor,\nand\ doesn't\ have\ any\ of\ the\ flaws\ above:\n\n\ \ \ \ \ \ \ \ entry\ \$path\ \{*\}\$args\n\nSo\ on\ to\ tcllib.\ \ I\ just\ grep\ the\ .tcl\ files\ for\ \"eval\"\ and\ let\ me\npick\ a\ few:\n\n#\ I\ sure\ hope\ critcl\ isn't\ in\ a\ dir\ with\ a\ space\n./sak.tcl:\ \ \ \ \ \ \ \ eval\ exec\ \$critcl\ -force\ \\\n\ \ \ \ \ \ \ \ -libdir\ \[list\ \$target\]\ -pkg\ \[list\ \$pkg\]\ \$files\n\n#\ Isn't\ this\ beautifully\ easy\ to\ understand?\n./modules/ftp/ftp.tcl:\ \ \ \ \ \ \ \ eval\ \[concat\ \$ftp(Output)\ \{\$s\ \$msg\ \$state\}\]\n\n#\ I\ sure\ hope\ they\ don't\ use\ namespaces\ with\ spaces,\ or\ cmds\ ...\n./modules/irc/irc.tcl:\ \ \ \ \ \ eval\ \[namespace\ current\]::cmd-\$cmd\ \$args\n\n#\ hmmm,\ just\ looks\ dangerous\ ...\n./modules/struct/record.tcl:\ \ \ \ eval\ Create\ \$def\ \$\{inst_\}.\$\{inst\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$cnt_plus\]\n\n#\ I'm\ not\ sure\ why\ eval\ was\ used\ here.\n#\ I\ think\ because\ version\ can\ be\ empty?\n./modules/stooop/mkpkgidx.tcl:\ \ eval\ package\ require\ \$name\ \$version\n\n#\ I\ think\ someone\ needs\ to\ look\ up\ \"concat\"\n./modules/textutil/adjust.tcl:\ \ lappend\ list\ \[\ eval\ list\ \$i\ \$words(\$i)\ 1\ \]\n\nOK\ ...\ so\ I'm\ tired\ of\ looking\ now.\n\n\ \ Jeff\ Hobbs\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ The\ Tcl\ Guy\n\ \ Senior\ Developer\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ http://www.ActiveState.com/\n\ \ \ \ \ \ \ \ Tcl\ Support\ and\ Productivity\ Solutions\n======\n\n\n**\ Caveat:\ List-Like\ Strings\ **\n\nThe\ arguments\ to\ `eval`\ are\ concatenated\ into\ a\ string\ to\ be\ interpreted,\ but\nThe\ arguments\ to\ \[\[eval\]\ are\ concatenated\ into\ a\ string\ to\ be\ interpreted,\ but\n(i.e.,\ one\ conforming\ to\ the\ Tcl\ parsing\ rules\ as\ laid\ out\ in\ the\ Tcl\ manual\npage).\n\nThe\ following\ script\ breaks\ because\ the\ concatenation\ keeps\ the\ newlines\ from\nthe\ list's\ string\ representation,\ making\ `eval`\ interpret\ the\ second\ element\nthe\ list's\ string\ representation,\ making\ \[\[eval\]\]\ interpret\ the\ second\ element\n\n======none\n%\ set\ arg\ \{a\nb\nc\n\}\na\nb\nc\n%\ eval\ list\ \$arg\nambiguous\ command\ name\ \"b\":\ bgerror\ binary\ break\n======\n\nTo\ solve\ this,\ construct\ the\ argument\ using\ list\ primitives\ like\ `\[lappend\]`,\nTo\ solve\ this,\ construct\ the\ argument\ using\ list\ primitives\ like\ \[lappend\],\n\[list\],\ etc.\ \ DKF\ says:\ \ \"list\ and\ eval\ are\ truly\ made\ for\ each\ other.\"\nAnother\ solution\ is\ to\ use\ the\ following\ idiom:\n\n======none\n%\ eval\ \[linsert\ \$arg\ 0\ list\]\na\ b\ c\n======\n\n`\[linsert\]`\ converts\ its\ list\ argument\ to\ a\ well-formed\ list\ with\ single\n`\[\[\[linsert\]\]`\ converts\ its\ list\ argument\ to\ a\ well-formed\ list\ with\ single\nof\ these\ elements\ contain\ newlines,\ they\ remain\ in\ the\ resulting\ string).\n\nIt's\ important\ to\ remember\ that\ `eval`\ works\ on\ '''strings''',\ not\ lists,\nIt's\ important\ to\ remember\ that\ `\[\[\[eval\]\]`\ works\ on\ '''strings''',\ not\ lists,\nfor\ interpreting\ a\ string\ as\ a\ script.\n\n\n**\ Verbose\ Evaluation\ **\n\n\[LV\]:\ I\ just\ had\ to\ copy\ this\ over\ to\ the\ wiki\ -\ it\ is\ so\ neat!\n\nFrom\ comp.lang.tcl,\ \[Bob\ Techentin\]\ writes\ in\ response\ to\ a\ poster:\n\nIt\ sounds\ like\ you're\ looking\ for\ something\ similar\ to\ /bin/sh\ \"set\ -v\"\ command\nwhich\ prints\ shell\ input\ lines\ as\ they\ are\ read,\ and\ \"set\ -x\"\ which\ prints\nexpanded\ commands.\ \ Kind\ of\ like\ a\ verbose\ mode.\n\nNope.\ \ Nothing\ like\ that.\ \ But\ you\ wouldn't\ have\ to\ write\ your\ own\ shell.\ \ You\ncould\ walk\ through\ a\ script\ (a\ list\ of\ lines),\ and\ use\ `\[info\ complete\]`\ to\ncould\ walk\ through\ a\ script\ (a\ list\ of\ lines),\ and\ use\ `\[\[\[info\ complete\]\]`\ to\ncommand\ and\ the\ command's\ results.\ \ This\ seems\ to\ work.\n\n======\nproc\ verbose_eval\ \{script\}\ \{\n\ \ \ \ set\ cmd\ \{\}\ \n\ \ \ \ set\ cmd\ \"\"\n\ \ \ \ if\ \{\$line\ eq\ \{\}\}\ \{continue\}\n\ \ \ \ if\ \{\$line\ eq\ \"\"\}\ \{continue\}\n\ \ \ \ \ \ \ \ if\ \{\[info\ complete\ \$cmd\]\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\ \[info\ complete\ \$cmd\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \[uplevel\ 1\ \$cmd\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ cmd\ \"\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nset\ script\ \{\n\ \ \ \ puts\ hello\n\ \ \ \ expr\ \{2.2\ *\ 3\}\n\ \ \ \ expr\ 2.2*3\n\nverbose_eval\ \$script\ \n======\n\n\[LV\]:\ This\ proc\ is\ so\ slick!\ I\ love\ it!\n\[LV\]\ This\ proc\ is\ so\ slick!\ I\ love\ it!\n\[Lars\ H\]:\ \ Another\ approach\ to\ this\ (which\ also\ can\ see\ individual\ commands\ in\n`\[if\]`\ branches,\ loop\ bodies,\ etc.)\ is\ to\ use\ `\[trace\]`s.\ Do\ we\ have\ that\ written\n\[if\]\ branches,\ loop\ bodies,\ etc.)\ is\ to\ use\ \[trace\]s.\ Do\ we\ have\ that\ written\n\n\[AR\]\ Here\ is\ my\ proposal\ with\ traces.\ Rem:\ the\ \"noop\"\ string\ is\ some\ kind\ of\ magic\ cookie.\n\n\n\[wtracy\]\ 2008-06-23:\ I\ want\ the\ commands\ I\ run\ in\ eval\ to\ have\ their\ own\ set\ of\nvariables\ independently\ of\ the\ calling\ script.\ Is\ there\ some\ way\ I\ can\ hand\neval\ a\ context\ (maybe\ as\ an\ associative\ array?).\n\n\[Lars\ H\]:\ Sounds\ like\ you\ want\ a\ \[lambda\]\ (or\ possibly\ a\ \[closure\],\ which\ is\nmore\ difficult).\ If\ you're\ using\ Tcl\ 8.5,\ then\ have\ a\ look\ at\ `\[apply\]`.\nmore\ difficult).\ If\ you're\ using\ Tcl\ 8.5,\ then\ have\ a\ look\ at\ `\[\[\[apply\]\]`.\n\[RS\]:\ Long\ before\ 8.5,\ you\ could\ always\ write\ a\ little\ proc\ to\ hide\ its\ local\nvariables\ (x\ in\ this\ example):\n\n======none\n%\ eval\ \{proc\ \{\}\ x\ \{expr\ \{\$x*\$x\}\}\;\ \{\}\ 5\}\n%\ eval\ \{proc\ \{\}\ x\ \{expr\ \$x*\$x\}\;\ \{\}\ 5\}\n======\n\n\[wtracy\]:\ Thanks.\ It\ looks\ like\ `\[apply\]`\ is\ the\ closest\ Tcl\ feature\ to\ what\n\[wtracy\]:\ Thanks.\ It\ looks\ like\ `\[\[\[apply\]\]`\ is\ the\ closest\ Tcl\ feature\ to\ what\n\n\[wtracy\]:\ Actually,\ it\ looks\ like\ what\ I\ *really*\ want\ is\ to\ nest\ `eval`\n\[wtracy\]:\ Actually,\ it\ looks\ like\ what\ I\ *really*\ want\ is\ to\ nest\ `\[\[eval\]`\ninside\ of\ a\ `\[\[\[namespace\ eval\]\]`\ block.\n\[wtracy\]:\ Okay,\ for\ the\ sake\ of\ any\ lost\ soul\ that\ comes\ along\ after\ me,\ this\nis\ what\ I\ really\ wanted\ to\ do\ all\ along:\n\n======none\n\$\ set\ cmd\ \{puts\ FOO\}\n>\ set\ cmd\ \{puts\ FOO\}\n\$\ namespace\ eval\ MyNameSpace\ \$cmd\n>\ namespace\ eval\ MyNameSpace\ \$cmd\n======\n\n\[NEM\]:\ As\ mentioned,\ `\[apply\]`\ is\ probably\ a\ better\ choice\ in\ this\ case\ as\ it\n\[NEM\]\ As\ mentioned,\ `\[\[\[apply\]\]`\ is\ probably\ a\ better\ choice\ in\ this\ case\ as\ it\n\[dangers\ of\ creative\ writing\]\ for\ some\ related\ discussion.\ The\ `\[apply\]`\ version\ is:\n\[dangers\ of\ creative\ writing\]\ for\ some\ related\ discussion.\ The\ apply\ version\ is:\n======\napply\ \{\{\}\ \{puts\ FOO\}\ ::MyNameSpace\}\napply\ \{\{\}\ \{\ puts\ FOO\ \}\ ::MyNameSpace\}\n\nThis\ has\ the\ benefit\ of\ evaluating\ the\ code\ within\ a\ fresh\ procedure\ context,\nmeaning\ all\ variables\ are\ local\n\nto\ that\ context\ by\ default.\ See\ also\ `\[namespace\ inscope\]`/`\[namespace\ code\]`\ and\nto\ that\ context\ by\ default.\ See\ also\ \[namespace\ inscope\]/\[namespace\ code\]\ and\nyou\ may\ also\ like\ \[dict\ with\].\n\n**\ Proposal:\ Modify\ `eval`\ to\ Accept\ a\ List\ of\ Lists\ \ **\n**\ Proposal:\ Modify\ `\[\[eval\]`\ to\ Accept\ a\ List\ of\ Lists\ \ **\nIn\ some\ cases\ `eval`\ does\ work\ on\ lists\ -\ and\ its\ special.\ \ In\ particular,\nIn\ some\ cases\ `\[\[\[eval\]\]`\ does\ work\ on\ lists\ -\ and\ its\ special.\ \ In\ particular,\nif\ eval\ is\ passed\ a\ \[pure\ list\]\ then\ it\ gets\ evaluated\ directly,\ without\nwhat\ it\ ''could''\ be.\n\nWhen\ you\ pass\ eval\ a\ pure\ list,\ you\ can\ only\ execute\ a\ single\ command.\ \ What\ if\nwe\ were\ to\ pass\ eval\ a\ list\ of\ pure\ lists\ -\ it\ should\ directly\ evaluate\ each\ of\nthem,\ and\ return\ the\ value\ of\ the\ the\ last\ one\ evaluated.\ \ This\ sounds\ a\ lot\nlike\ progn\ in\ \[lisp\],\ and\ it\ seems\ like\ it\ would\ allow\ for\ some\ nifty\ bits\ of\n\[introspection\]\ -\ for\ example,\ if\ `\[info\ body\]`\ returned\ a\ pure\ list\ of\ lists\n\[introspection\]\ -\ for\ example,\ if\ \[info\ body\]\ returned\ a\ pure\ list-of-lists\nwhole\ program\ becomes\ a\ list\ of\ lists.\n\nThe\ problem\ is\ how\ to\ signal\ to\ `eval`\ (or\ `\[uplevel\]`,\ `\[namespace\]`,\ `\[bind\]`,\ ...)\ that\ it\nThe\ problem\ is\ how\ to\ signal\ to\ eval\ (or\ uplevel,\ namespace,\ bind,\ ...)\ that\ it\nis\ a\ list\ of\ lists\ rather\ than\ just\ a\ list.\ \ Could\ eval\ determine\ if\ its\ input\nprogn?\n\nAnother\ place\ this\ seems\ like\ it\ could\ be\ useful:\ I\ have\ a\ \[pkgIndex.tcl\]\ file\ with\nAnother\ place\ this\ seems\ like\ it\ could\ be\ useful:\ I\ have\ a\ pkgIndex\ file\ with\n\npackage\ ifneeded\ tls\ 1.4\ \[\npackage\ ifneeded\ tls\ 1.4\ \"\[list\ load\ \[file\ join\ \$dir\ libtls1.4.so\]\]\;\[list\ source\ \[file\ join\ \$dir\ tls.tcl\]\]\"\n\nwhere\ most\ of\ the\ lines\ are\ like\n\n======\npackage\ ifneeded\ tclperl\ 2.3\ \[list\ load\ \[file\ join\ \$dir\ tclperl.so\]\]\n======\n\nsince\ they\ only\ need\ one\ command\;\ but\ the\ tls\ line\ needs\ two\ commands.\ \ So\ why\ can't\ it\ be\n\n======\npackage\ ifneeded\ tls\ 1.4\ \[list\ \[\npackage\ ifneeded\ tls\ 1.4\ \[list\ \[list\ load\ \[file\ join\ \$dir\ libtls1.4.so\]\]\ \[list\ source\ \[file\ join\ \$dir\ tls.tcl\]\]\]\n\n\n\n\n\[RS\]\ 2004-02-06:\ As\ usual\ in\ Tcl,\ functionality\ you\ miss\ you\ can\ easy\ roll\nyourself.\ I\ needed\ a\ progn-like\ list\ eval\ in\ \[RPN\ again\],\ and\ did\ it\ similar\ to\nthis:\n\n======\nproc\ leval\ args\ \{\n\ \ \ \ foreach\ arg\ \$args\ \{\n\ \ \ \ \ \ \ \ set\ res\ \[uplevel\ 1\ \$arg\]\n\ \ \ \ \}\n\ \ \ \ set\ res\ \;#\ return\ last\ (\"n-th\")\ result,\ as\ Tcl\ evaluation\ does\n\}\n======\n\n\n\n**\ eval\ versus\ bytecode\ **\n**\ `eval`\ versus\ bytecode\ **\n\[AMG\]:\ It\ appears\ `\[\[eval\]\]`'ed\ code\ does\ not\ get\ \[bytecode\]-compiled,\ even\nwhen\ \[\[eval\]\]\ is\ passed\ a\ single\ brace-quoted\ argument.\ \ The\ same\ is\ true\ for\n`\[\[\[uplevel\]\ 0\]`\ and\ `\[\[\[time\]\]`.\ \ `\[\[\[catch\]\]`\ and\ `\[\[\[if\]\ \{1\}\]\]`\ seem\ to\ be\n\"argument\",\ rather\ a\ single\ command\ line\ pre-chewed\ into\ an\ objv\ list.\nBytecoding\ cannot\ take\ place\ when\ the\ argument\ is\ the\ product\ of\ `\[list\]`,\nBytecoding\ cannot\ take\ place\ when\ the\ argument\ is\ the\ product\ of\ `\[\[\[list\]\]`,\n\n======\nproc\ a\ \{\}\ \{eval\ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ b\ \{\}\ \{uplevel\ 0\ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ c\ \{\}\ \{time\ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ d\ \{\}\ \{catch\ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ e\ \{\}\ \{if\ \{1\}\ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ f\ \{\}\ \{\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ g\ \{\}\ \{eval\ \ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ h\ \{\}\ \{uplevel\ 0\ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ i\ \{\}\ \{time\ \ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ j\ \{\}\ \{catch\ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ k\ \{\}\ \{if\ \{1\}\ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ l\ \{\}\ \{\ \ \ \ \ \ \ \{*\}\[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ m\ \{\}\ \{try\ \ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\na\;b\;c\;d\;e\;f\;g\;h\;i\;j\;k\;l\;m\ntime\ a\ 10\ \ \ \ \;#\ \ 80723.8\ microseconds\ per\ iteration\ -\ slow\ntime\ b\ 10\ \ \ \ \;#\ \ 65380.2\ microseconds\ per\ iteration\ -\ slow\ntime\ c\ 10\ \ \ \ \;#\ \ 66024.8\ microseconds\ per\ iteration\ -\ slow\ntime\ d\ 100\ \ \ \;#\ \ 18888.3\ microseconds\ per\ iteration\ -\ fast\ntime\ e\ 100\ \ \ \;#\ \ 18779.3\ microseconds\ per\ iteration\ -\ fast\ntime\ f\ 100\ \ \ \;#\ \ 19375.2\ microseconds\ per\ iteration\ -\ fast\ntime\ g\ 10\ \ \ \ \;#\ 319111.5\ microseconds\ per\ iteration\ -\ very\ slow\ntime\ h\ 10\ \ \ \ \;#\ 342878.4\ microseconds\ per\ iteration\ -\ very\ slow\ntime\ i\ 10\ \ \ \ \;#\ 322279.2\ microseconds\ per\ iteration\ -\ very\ slow\ntime\ j\ 10\ \ \ \ \;#\ 316939.0\ microseconds\ per\ iteration\ -\ very\ slow\ntime\ k\ 10\ \ \ \ \;#\ 321865.5\ microseconds\ per\ iteration\ -\ very\ slow\ntime\ l\ 10\ \ \ \ \;#\ 344009.5\ microseconds\ per\ iteration\ -\ very\ slow\ntime\ m\ 100\ \ \ \;#\ \ 19503.0\ microseconds\ per\ iteration\ -\ fast\n======\n\nI\ want\ single-argument\ `eval`\ functionality\ in\ my\ code,\ but\ I\ also\ want\nI\ want\ single-argument\ `\[\[\[eval\]\]`\ functionality\ in\ my\ code,\ but\ I\ also\ want\nbytecoding.\ \ `\[\[\[catch\]\]`\ has\ the\ undesirable\ side\ effect\ of\ hiding\ errors,\ so\nI\ guess\ I\ have\ to\ use\ `\[\[\[if\]\ \{1\}\]`\ which\ is\ a\ really\ weird\ idiom.\ \ Does\ anyone\n\n\[AMG\]:\ I\ reran\ the\ tests\ and\ got\ better\ numbers.\ \ The\ current\ version\ of\ Tcl\nmust\ be\ faster\ than\ whatever\ I\ used\ when\ I\ first\ did\ this\ benchmark\ (I'm\ using\nthe\ same\ computer).\ \ Look\ in\ the\ page\ history\ to\ see\ the\ comparison.\ \ More\nimportantly,\ I\ think\ I\ found\ a\ bytecoded\ `eval`:\ single-argument\ `\[try\]`.\nimportantly,\ I\ think\ I\ found\ a\ bytecoded\ \[\[eval\]\]:\ single-argument\ \[\[\[try\]\]\].\nmethods.\ \ It's\ considerably\ less\ weird\ than\ `\[if\]\ 1`,\ and\ it\ doesn't\ hide\nmethods.\ \ It's\ considerably\ less\ weird\ than\ \[\[if\ \{1\}\]\],\ and\ it\ doesn't\ hide\n\n\[DKF\]:\ We've\ been\ focusing\ a\ bit\ more\ on\ improving\ the\ most\ cripplingly-slow\ncases,\ but\ three\ execution\ modes\ still\ exist\ that\ have\ fundamentally\ different\nspeeds.\ There's\ compilation\ to\ bytecode-with-local-var-table\ (which\ is\ the\nfastest\;\ the\ speed\ comes\ from\ being\ able\ to\ compile\ in\ indexes\ into\ the\ LVT\ninto\ the\ generated\ bytecode,\ which\ this\ test\ is\ particularly\ sensitive\ to),\nthere's\ compilation\ to\ bytecode-without-LVT\ (slower\;\ variables\ have\ to\ be\nlooked\ up\ each\ time\ they're\ accessed),\ and\ there's\ interpreting\ (slowest\ by\nfar).\ There's\ not\ much\ point\ in\ doing\ a\ lot\ of\ comparison\ between\ the\ three\;\nthey\ all\ exist\ for\ a\ reason.\ (We\ could\ make\ straight\ `eval`/`\[uplevel\]\nthey\ all\ exist\ for\ a\ reason.\ (We\ could\ make\ straight\ '''eval'''/'''\[uplevel\]\n0'''\ of\ constant\ arguments\ work\ at\ full\ speed,\ but\ we\ see\ no\ reason\ to\ bother\ngiven\ how\ rare\ they\ are\ in\ real\ code,\ and\ it's\ better\ that\ \[time\]\ is\ kept\nto\ get\ by\ using\ `\[::tcl::unsupported::disassemble\]`\ to\ look\ at\ the\ bytecode\ to\ see\nto\ get\ by\ using\ \[tcl::unsupported::disassemble\]\ to\ look\ at\ the\ bytecode\ to\ see\ndone\ by\ just\ building\ arguments\ and\ invoking\ “cnormal”\ commands.\ndone\ by\ just\ building\ arguments\ and\ invoking\ “normal”\ commands.\n\[Twylite\]\ 2012-08-24:\ \ I've\ been\ optimising\ some\ control\ constructs\ and\ was\ntrying\ to\ understand\ the\ performance\ of\ various\ combinations\ of\ uplevel,\ntailcall,\ catch\ and\ try.\ \ Along\ the\ way\ I\ found\ \[AMG\]'s\ performance\ figures,\nand\ have\ updated\ them\ with\ some\ new\ ones:\n\n======\n#\ Fast\ (prefix\ f)\nproc\ f_baseline\ \ \ \ \ \ \ \{\}\ \{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\ \}\nproc\ f_catch\ \ \ \ \ \ \ \ \ \ \{\}\ \{catch\ \ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ f_catch\ \ \ \ \ \ \ \ \ \ \{\}\ \{catch\ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ f_if_1\ \ \ \ \ \ \ \ \ \ \ \{\}\ \{if\ \{1\}\ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ f_expand\ \ \ \ \ \ \ \ \ \{\}\ \{\ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ f_try\ \ \ \ \ \ \ \ \ \ \ \ \{\}\ \{try\ \ \ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ f_time_apply\ \ \ \ \ \{\}\ \{time\ \{apply\ \{\{\}\ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\}\}\n#\ Medium\ (prefix\ m)\ \ \ \ \ \ \ \ \ \ \ \ \ \nproc\ m_eval\ \ \ \ \ \ \ \ \ \ \ \{\}\ \{eval\ \ \ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ m_eval\ \ \ \ \ \ \ \ \ \ \ \{\}\ \{eval\ \ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ m_uplevel_0\ \ \ \ \ \ \{\}\ \{uplevel\ 0\ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ m_time\ \ \ \ \ \ \ \ \ \ \ \{\}\ \{time\ \ \ \ \ \ \ \ \ \ \ \ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ m_tailcall_try\ \ \ \{\}\ \{tailcall\ \ \ \ try\ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\}\nproc\ m_catch_uplvl_1\ \ \{\}\ \{\ \ \ \ \ \ \ set\ body\ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\ \;\ catch\ \{\ uplevel\ 1\ \$body\ \}\ \}\ \ \nproc\ m_uplvl_1_catch\ \ \{\}\ \{\ \ \ \ \ \ \ set\ body\ \{for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\}\ \;\ uplevel\ 1\ \[list\ catch\ \$body\]\ \}\ \ \n#\ Slow\ (prefix\ s)\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \nproc\ s_eval_list\ \ \ \ \ \ \{\}\ \{eval\ \ \ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ s_uplevel_0_list\ \{\}\ \{uplevel\ 0\ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ s_time_list\ \ \ \ \ \ \{\}\ \{time\ \ \ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ s_catch_list\ \ \ \ \ \{\}\ \{catch\ \ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ s_if_1_list\ \ \ \ \ \ \{\}\ \{if\ 1\ \ \ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ s_if_1_list\ \ \ \ \ \ \{\}\ \{if\ \{1\}\ \ \ \ \ \[list\ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\]\}\nproc\ s_tailcall\ \ \ \ \ \ \ \{\}\ \{tailcall\ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 100000\}\ \{incr\ i\}\ \{\}\ \}\n\nif\ 0\ \{\nif\ \{0\}\ \{\n\ \ set\ REPS\ \{f\ 10\ m\ 40\ s\ 100\}\ \;#\ reps\ by\ prefix\n\ \ set\ cmds\ \{f_baseline\ f_catch\ f_if_1\ f_expand\ f_try\ f_time_apply\ \n\ \ \ \ m_eval\ m_uplevel_0\ m_time\ m_tailcall_try\ m_catch_uplvl_1\ m_uplvl_1_catch\ \n\ \ \ \ s_eval_list\ s_uplevel_0_list\ s_time_list\ s_catch_list\ s_if_1_list\ \n\ \ \ \ s_expand_list\ s_tailcall\}\n\ \ \n\ \ foreach\ cmd\ \$cmds\ \{\ \$cmd\ \}\ \;#\ compile\n\ \ set\ cmdrepstimes\ \{\}\ \;\ foreach\ cmd\ \$cmds\ \{\ \;#\ time\n\ \ \ \ set\ reps\ \[dict\ get\ \$::REPS\ \[string\ index\ \$cmd\ 0\]\]\ \n\ \ \ \ lappend\ cmdrepstimes\ \[lindex\ \[time\ \$cmd\ \$reps\]\ 0\]\ \$cmd\ \$reps\ \n\ \ \}\n\ \ \n\ \ set\ mintime\ \[::tcl::mathfunc::min\ \{*\}\$times\]\n\ \ foreach\ \{t\ cmd\ reps\}\ \[lsort\ -real\ -stride\ 3\ \$cmdrepstimes\]\ \{\n\ \ \ \ puts\ \[format\ \"time\ %-16s\ \$reps\\t\;#\ %9.1f\ microseconds\ per\ iteration,\ factor\ %5.2f\"\ \\\n\ \ \ \ \ \ \$cmd\ \$t\ \[expr\ \{\ \$t\ /\ \$mintime\ \}\]\ \]\ \n\ \ \}\n\ntime\ f_time_apply\ \ \ \ \ 10\ \ \ \ \ \ \ \ \;#\ \ \ \ 4625.8\ microseconds\ per\ iteration,\ factor\ \ 1.00\ntime\ f_if_1\ \ \ \ \ \ \ \ \ \ \ 10\ \ \ \ \ \ \ \ \;#\ \ \ \ 4641.8\ microseconds\ per\ iteration,\ factor\ \ 1.00\ntime\ f_expand\ \ \ \ \ \ \ \ \ 10\ \ \ \ \ \ \ \ \;#\ \ \ \ 4645.0\ microseconds\ per\ iteration,\ factor\ \ 1.00\ntime\ f_catch\ \ \ \ \ \ \ \ \ \ 10\ \ \ \ \ \ \ \ \;#\ \ \ \ 4651.3\ microseconds\ per\ iteration,\ factor\ \ 1.00\ntime\ f_baseline\ \ \ \ \ \ \ 10\ \ \ \ \ \ \ \ \;#\ \ \ \ 4658.5\ microseconds\ per\ iteration,\ factor\ \ 1.01\ntime\ f_try\ \ \ \ \ \ \ \ \ \ \ \ 10\ \ \ \ \ \ \ \ \;#\ \ \ \ 4735.9\ microseconds\ per\ iteration,\ factor\ \ 1.02\ntime\ m_eval\ \ \ \ \ \ \ \ \ \ \ 40\ \ \ \ \ \ \ \ \;#\ \ \ 18454.3\ microseconds\ per\ iteration,\ factor\ \ 3.98\ntime\ m_uplevel_0\ \ \ \ \ \ 40\ \ \ \ \ \ \ \ \;#\ \ \ 18738.3\ microseconds\ per\ iteration,\ factor\ \ 4.04\ntime\ m_time\ \ \ \ \ \ \ \ \ \ \ 40\ \ \ \ \ \ \ \ \;#\ \ \ 19176.8\ microseconds\ per\ iteration,\ factor\ \ 4.14\ntime\ m_uplvl_1_catch\ \ 40\ \ \ \ \ \ \ \ \;#\ \ \ 21501.1\ microseconds\ per\ iteration,\ factor\ \ 4.64\ntime\ m_catch_uplvl_1\ \ 40\ \ \ \ \ \ \ \ \;#\ \ \ 21603.1\ microseconds\ per\ iteration,\ factor\ \ 4.66\ntime\ m_tailcall_try\ \ \ 40\ \ \ \ \ \ \ \ \;#\ \ \ 21698.4\ microseconds\ per\ iteration,\ factor\ \ 4.68\ntime\ s_uplevel_0_list\ 100\ \ \ \ \ \ \ \;#\ \ \ 84963.3\ microseconds\ per\ iteration,\ factor\ 18.34\ntime\ s_eval_list\ \ \ \ \ \ 100\ \ \ \ \ \ \ \;#\ \ \ 85519.3\ microseconds\ per\ iteration,\ factor\ 18.46\ntime\ s_catch_list\ \ \ \ \ 100\ \ \ \ \ \ \ \;#\ \ \ 85919.9\ microseconds\ per\ iteration,\ factor\ 18.54\ntime\ s_time_list\ \ \ \ \ \ 100\ \ \ \ \ \ \ \;#\ \ \ 85944.2\ microseconds\ per\ iteration,\ factor\ 18.55\ntime\ s_if_1_list\ \ \ \ \ \ 100\ \ \ \ \ \ \ \;#\ \ \ 87269.0\ microseconds\ per\ iteration,\ factor\ 18.84\ntime\ s_expand_list\ \ \ \ 100\ \ \ \ \ \ \ \;#\ \ \ 93096.9\ microseconds\ per\ iteration,\ factor\ 20.09\ntime\ s_tailcall\ \ \ \ \ \ \ 100\ \ \ \ \ \ \ \;#\ \ \ 94473.5\ microseconds\ per\ iteration,\ factor\ 20.39\n======\n\n\n} CALL {my revision eval} CALL {::oo::Obj852175 process revision/eval} CALL {::oo::Obj852173 process}

-errorcode

NONE

-errorinfo

Unknow state transition: LINE -> END
    while executing
"error $msg"
    (class "::Wiki" method "render_wikit" line 6)
    invoked from within
"my render_$default_markup $N $C $mkup_rendering_engine"
    (class "::Wiki" method "render" line 8)
    invoked from within
"my render $name $C"
    (class "::Wiki" method "revision" line 31)
    invoked from within
"my revision $page"
    (class "::Wiki" method "process" line 56)
    invoked from within
"$server process [string trim $uri /]"

-errorline

4