Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/Gadgets?V=8
QUERY_STRINGV=8
CONTENT_TYPE
DOCUMENT_URI/revision/Gadgets
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR172.71.223.187
REMOTE_PORT14132
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR3.235.227.36
HTTP_CF_RAY86b93c102d6f1fd9-IAD
HTTP_X_FORWARDED_PROTOhttps
HTTP_CF_VISITOR{"scheme":"https"}
HTTP_ACCEPT*/*
HTTP_USER_AGENTclaudebot
HTTP_CF_CONNECTING_IP3.235.227.36
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 Gadgets \[Richard\ Suchenwirth\]\ --\ I\ have\ toyed\ with\ the\ gadget\ concept\ every\ now\ and\ then\ for\ years\ now\ (see\ \[tally:\ a\ string\ counter\ gadget\]\ or\ \[A\ matrix\ gadget\]),\ but\ here's\ a\ generalized\ approach.\ See\ also\ \[LOST\]\ for\ Larry\ Smith's\ extension\ to\ that..\ and\ \[On\ Things\]\ for\ a\ more\ radical\ typeless\ approach.\n\nI\ call\ gadgets\ \"poor\ man's\ objects\"\ -\ basically\ they\ are\ a\ variable\ (string,\ list\ or\ array)\ and\ a\ proc,\ both\ with\ the\ same\ name.\ The\ proc\ is\ renamed\ away\ when\ the\ variable\ dies.\ No\ inheritance\ (yet),\ no\ namespaces\ involved,\ but\ they\ offer\ a\ slick\ Tk-like\ API\ where\ you\ call\ the\ gadget's\ name\ with\ a\ minor\ command\ (method\ name)\ and\ possibly\ other\ parameters.\ \n\nFirst,\ a\ look\ at\ the\ generalized\ API.\ You\ can\ specify\ a\ gadget\ type\ with\ methods,\ in\ which\ you\ can\ refer\ to\ 'args'\ for\ the\ method's\ arguments\ (parse'em\ yourself\ \;-)\ and\ 'self'\ for\ the\ variable\ itself,\ like\ this:\n\n======\ngadget\ type\ number\ \{\n\ \ \ =\ \ \ \ \ \{set\ self\ \[expr\ \$args\]\}\n\ \ \ ++\ \ \ \ \{set\ self\ \[expr\ \$self+1\]\}\n\ \ \ round\ \{set\ self\ \[expr\ round(\$self)\]\}\ \n\ \ \ sqrt\ \ \{expr\ sqrt(\$self)\}\ \n\}\ngadget\ type\ int\ \{\n\ \ \ =\ \ \{set\ self\ \[expr\ round(\$args)\]\}\n\ \ \ ++\ \{incr\ self\}\n\}\ngadget\ type\ Array\ \{\n\ \ \ =\ -\ +=\ \{eval\ array\ set\ self\ \$args\ \}\n\ \ \ -=\ \ \ \ \ \{catch\ \{unset\ self(\$args)\}\}\n\ \ \ @\ \ \ \ \ \ \{set\ self(\$args)\}\n\ \ \ empty\ \ \{expr\ \[array\ size\ self\]==0\}\n\ \ \ names\ \ \{array\ names\ self\}\n\ \ \ \{\}\ \ \ \ \ \{array\ get\ self\}\n\}\ngadget\ type\ List\ \{\n\ \ \ =\ \ \ \ \ \ \{eval\ set\ self\ \$args\}\n\ \ \ +=\ \ \ \ \ \{lappend\ self\ \$args\}\n\ \ \ @\ \ \ \ \ \ \{lindex\ \$self\ \$args\}\n\ \ \ empty\ \ \{expr\ \[llength\ \$self\]==0\}\n\ \ \ sort\ \ \ \{lsort\ \$self\}\n\ \ \ length\ \{llength\ \$self\}\n\}\ngadget\ type\ File\ \{\n\ \ =\ \ \ \ \ \{set\ self\ \[eval\ open\ \$args\]\}\n\ \ >>\ \ \ \ \{upvar\ \$args\ var\;\ expr\ \[gets\ \$self\ var\]+1\}\n\ \ <<\ \ \ \ \{puts\ \$self\ \$args\}\n\ \ eof\ \ \ \{eof\ \$self\}\n\ \ open?\ \{expr\ !\[catch\ \{seek\ \$self\ 0\ current\}\]\}\n\ \ close\ \{close\ \$self\}\ \n\}\n======\nFor\ a\ defined\ gadget\ type,\ you\ can\ call\ a\ \"constructor\"\ with\ a\ name,\ and\ possibly\ an\ initialization:\n\n=====\nnumber\ N\ =\ 1.5\nArray\ A\nList\ L\ =\ \{foo\ bar\}\n======\n\nFor\ a\ \"destructor\",\ we\ just\ reuse\ the\ good\ old\ ''unset''\ wheel.\n\nNow\ you\ can\ use\ these\ variables\ or\ procs\ as\ you\ wish,\ with\ the\ addition\ that\ calling\ a\ (non-array)\ gadget\ proc\ without\ arguments\ returns\ its\ value,\ so\ \[\[N\]\]\ is\ a\ new\ alternative\ to\ \$N\ and\ \[\[set\ N\]\]:\n\n======\nN\ =\ \[N\]\ *\ \$N\ \ \ \ \ \ \ \ ->\ 2.25\ (just\ for\ the\ fun\ of\ it\ \;)\nset\ A(cat)\ Katze\ \ \ \ ->\ Katze\nA\ names\ \ \ \ \ \ \ \ \ \ \ \ \ ->\ cat\nL\ +=\ grill\nL\ =\ \[L\ sort\]\nputs\ \"\[L\]\ has\ \[L\ length\]\ elements,\ second\ is\ \[L\ @\ 1\]\"\n->\ bar\ foo\ grill\ has\ 3\ elements,\ second\ is\ foo\nFile\ F\ =\ gadget.tcl\nint\ i\ =\ 1\nwhile\ \{\[F\ >>\ line\]\}\ \{\n\ \ \ \ puts\ \[i\]:\$line\n\ \ \ \ i\ ++\n\}\nF\ close\n======\n\nYes,\ this\ is\ still\ Tcl,\ and\ no,\ it's\ not\ like\ in\ the\ book.\ You\ can\ adjust\ the\ language\ pretty\ much\ to\ your\ likings\ via\ the\ method\ names.\nArithmetic\ assignments\ look\ almost\ like\ all\ the\ world\ expects\ them\ to\ look\ (cf.\ \[Radical\ language\ modification\],\ where\ I\ tried\ the\ same\ goal\ with\ the\ unknown\ command),\ and\ by\ pressing\ the\ assigned\ value\ through\ expr\ in\ the\ \"number\ =\"\ or\ \"int\ =\"\ method,\ some\ typechecking\ is\ introduced.\ \n\nThe\ polymorphism\ (same\ method\ names\ for\ different\ types)\ allows\ some\ hiding\ of\ internal\ quirks,\ e.g.\ now\ you\ can\ increment\ a\ ''double''\ like\ an\ ''int''\ with\ ++,\ by\ just\ adding\ 1\ to\ it\ resp.\ calling\ incr.\ Notice\ also\ the\ polymorphism\ of\ +=\ for\ lists\ vs.\ arrays:\ append\ an\ element,\ or\ set\ a\ key-value\ pair.\n\nFor\ introspection,\ you\ can\ get\ the\ types\ and\ names\ defined,\ and\ each\ gadget\ tells\ his\ type\ if\ asked:\n\n======\ngadget\ types\ \ \ \ \ ->\ number\ int\ Array\ List\ File\ngadget\ names\ \ \ \ \ ->\ N\ A\ L\ F\nN\ type\ \ \ \ \ \ \ \ \ \ \ ->\ number\n======\n\nBook-keeping\ of\ names\ and\ types\ is\ done\ not\ with\ global\ variables,\ but\ with\ procs\ whose\ bodies\ are\ rewritten\ when\ needed.\ The\ calls\ to\ ''proc\ gadget:names''\ show\ how\ that's\ done:\ start\ with\ a\ argumentless\ list\ command,\ append\ a\ new\ name\ on\ gadget\ creation,\ lreplace\ the\ name\ out\ on\ gadget\ destruction.\n\nOK,\ so\ here's\ the\ code\ that\ does\ that\ (not\ very\ long,\ but\ not\ the\ easiest\ reading\ either\ -\ after\ all\ you\ write\ a\ proc\ that\ writes\ a\ proc\ that\ writes\ a\ proc\ \;-):\nThe\ switch\ line\ containing\ 'type'\ did\ not\ work\ on\ my\ system:\ adding\ eval\ worked\ like\ a\ charm.\ \ Has\ there\ been\ a\ change\ in\ how\ the\ switch\ command\ works\ since\ 2002?\ --\ Jim\ Hinds\n\n======\nproc\ gadget\ \{cmd\ args\}\ \{\n\ \ \ \ switch\ --\ \$cmd\ \{\n\ \ \ \ \ \ \ \ names\ \ \ \{gadget:names\}\n\ \ \ \ \ \ \ \ type\ \ \ \ \{gadget:type\ \$args\ \;\ #\ This\ command\ needed\ eval\ as\ in\ \{eval\ gadget:type\ \$args\}\ JH\ \ \}\n\ \ \ \ \ \ \ \ types\ \ \ \{gadget:types\}\n\ \ \ \ \ \ \ \ default\ \{return\ -code\ error\ \"\$cmd?\ should\ be\ name,\ type,\ or\ types\"\}\n\ \ \ \ \}\n\}\nproc\ gadget:types\ \{\}\ \{list\}\nproc\ gadget:names\ \{\}\ \{list\}\n\nproc\ gadget:type\ \{type\ methods\}\ \{\n\ \ \ \ if\ \{\[info\ commands\ \$type\]!=\"\"\}\ \{\n\ \ \ \ \ \ \ \ return\ -code\ error\ \"type\ \$type\ redefines\ existing\ command\"\n\ \ \ \ \}\n\ \ \ \ proc\ gadget:types\ \{\}\ \{concat\ \[info\ body\ gadget:types\]\ \$type\}\n\ \ \ \ set\ template\ \{\n\ \ \ \ \ \ \ \ proc\ @type@\ \{name\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$name==\"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ name\ \[lindex\ \$args\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ upvar\ 2\ \$name\ self\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rest\ \[lindex\ \$args\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cmd\ \ \[lindex\ \$rest\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ args\ \[lrange\ \$rest\ 1\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ --\ \$cmd\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ type\ \{return\ @type@\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ @methods@\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{\}\ \{set\ self\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ default\ \{return\ -code\ error\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\$cmd?\ Should\ be\ one\ of\ \[join\ \[list\ type\ @cmds@\]\]\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ commands\ \$name\]!=\"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"gadget\ \$name\ redefines\ existing\ command\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uplevel\ trace\ variable\ \$name\ u\ gadget:unset\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ proc\ gadget:names\ \{\}\ \{concat\ \[info\ body\ gadget:names\]\ \$name\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ proc\ \$name\ \{args\}\ \"@type@\ \{\}\ \$name\ \\\$args\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \[llength\ \$args\]\ \{uplevel\ \ \$name\ \$args\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ cmds\ \[list\]\n\ \ \ \ foreach\ \{cmd\ -\}\ \$methods\ \{lappend\ cmds\ \$cmd\}\n\ \ \ \ regsub\ -all\ @cmds@\ \ \ \ \$template\ \$cmds\ \ \ \ template\n\ \ \ \ regsub\ -all\ @type@\ \ \ \ \$template\ \$type\ \ \ \ template\n\ \ \ \ regsub\ -all\ @methods@\ \$template\ \$methods\ template\n\ \ \ \ eval\ \$template\n\ \ \ \ set\ type\n\}\n\nproc\ gadget:unset\ \{name\ el\ -\}\ \{\n\ \ \ \ if\ \{\$el==\"\"\}\ \{\n\ \ \ \ \ \ \ \ rename\ \$name\ \"\"\n\ \ \ \ \ \ \ \ set\ names\ \[info\ body\ gadget:names\]\n\ \ \ \ \ \ \ \ set\ where\ \[lsearch\ \$names\ \$name\]\n\ \ \ \ \ \ \ \ proc\ gadget:names\ \{\}\ \[lreplace\ \$names\ \$where\ \$where\]\n\ \ \ \ \}\ \ \n\}\n======\n\n'''Notes''':\ Gadgets\ can\ be\ passed\ by\ name\ in\ proc\ calls,\ where\ you\ either\ reuse\ the\ same\ name,\ or\ register\ the\ upvar\ variable:\n\n======\nupvar\ \$name\ \$name\ \;#\ or:\nupvar\ \$name\ var\;\ \[\$name\ type\]\ var\n======\n\nAs\ their\ procs\ are\ (of\ course)\ global,\ gadget\ names\ must\ be\ unique\ and\ may\ not\ use\ existing\ command\ (C\ or\ Tcl)\ names.\ This\ prevents\ one\ from\ accidentally\ rewriting\ \"set\"\ or\ other\ Tcl\ essentials.\ Drawback:\ gadgets\ with\ same\ name\ cannot\ be\ used\ in\ recursive\ procs.\n\n----\n\n\ \ \ *\ Shorter\ and\ Sweeter:\n\n\[Larry\ Smith\]\ (mailto:larry(...at\ sign...)smith-house.org)\ reverse-engineered\ an\ example\ I\ put\ on\ comp.lang.tcl\ and\ came\ to\ this\ beautiful\ short\ solution:\n\n======\nproc\ gadget\ \{\ unused\ type\ methods\ \}\ \{\n\ \ \ \ set\ typeproc\ \{\n\ \ \ \ \ \ \ \ set\ typeproc\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ @var\ self\n\ \ \ \ \ \ \ \ \ \ \ \ @type\ self\ \$method\ \$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ upvar\ \$var\ self\n\ \ \ \ \ \ \ \ if\ \{\ \"\$method\"\ ==\ \"\"\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$self\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ switch\ \$method\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ @methods\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ regsub\ @var\ \$typeproc\ \$var\ typeproc\n\ \ \ \ \ \ \ \ proc\ \$var\ \{\ \{\ method\ \"\"\ \}\ args\ \}\ \$typeproc\n\ \ \ \ \}\n\ \ \ \ regsub\ @type\ \$typeproc\ \$type\ typeproc\n\ \ \ \ regsub\ @methods\ \$typeproc\ \$methods\ typeproc\n\ \ \ \ proc\ \$type\ \{\ var\ method\ args\ \}\ \$typeproc\n\}\n======\n\nI\ find\ it\ more\ legible,\ though,\ if\ all\ four\ mentions\ of\ ''typeproc''\ inside\ the\ first\ ''set\ typeproc\ ..''\ are\ replaced\ by\ ''instproc'',\ as\ that\ is\ dealing\ with\ the\ instance\ proc\ anyway.\ -\ RS\n\n\[AMG\]:\ The\ \[\[\[regsub\]\]\]s\ can\ be\ replaced\ with\ \[\[\[string\ map\]\]\]s:\n\n======\nproc\ \$var\ \{\{method\ \"\"\}\ args\}\ \[string\ map\ \[list\ @var\ \$var\]\ \$typeproc\]\nproc\ \$type\ \{var\ method\ args\}\ \[string\ map\ \[list\ @type\ \$type\ @methods\ \$methods\]\ \$typeproc\]\n======\n\nWhoa,\ to\ avoid\ unwanted\ expansion,\ better\ put\ an\ extra\ level\ of\ listiness\ in\ there:\n\n======\n\[string\ map\ \[list\ @var\ \[list\ \$var\]\]\ \$typeproc\]\n======\n\nYou\ can\ even\ lose\ the\ \$typeproc\ variables,\ instead\ directly\ including\ the\ template.\ \ To\ make\ things\ easier\ still,\ make\ a\ helper\ procedure\ to\ do\ the\ string\ mapping.\ \ Yet\ more:\ make\ that\ helper\ procedure\ itself\ make\ procedures!\n\n======\nproc\ proc_template\ \{name\ lazy_args\ eager_args\ body\}\ \{\n\ \ \ \ set\ map\ \[list\]\n\ \ \ \ foreach\ varname\ \$eager_args\ \{\n\ \ \ \ \ \ \ \ upvar\ 1\ \$varname\ var\n\ \ \ \ \ \ \ \ lappend\ map\ @\$varname@\ \[list\ \$var\]\n\ \ \ \ \}\n\ \ \ \ proc\ \$name\ \$lazy_args\ \[string\ map\ \$map\ \$body\]\n\}\n\nproc\ gadget\ \{unused\ type\ methods\}\ \{\n\ \ \ \ proc_template\ \$type\ \{var\ method\ args\}\ \{type\ methods\}\ \{\n\ \ \ \ \ \ \ \ upvar\ \$var\ self\n\ \ \ \ \ \ \ \ if\ \{\$method\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$self\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ switch\ \$method\ @methods@\n\ \ \ \ \ \ \ \ proc_template\ \$var\ \{\{method\ \"\"\}\ args\}\ \{var\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ @var@\ self\n\ \ \ \ \ \ \ \ \ \ \ \ @type@\ self\ \$method\ \$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n======\n\nThere's\ a\ pitfall\ here,\ though:\n\n======none\ngadget\ type\ @var@\ \{=\ \{set\ self\ \[expr\ \$args\]\}\}\n@var@\ name\ =\ 5\nname\nERROR:\ too\ many\ nested\ evaluations\n======\n\nThe\ outer\ \[\[proc_template\]\]\ expands\ the\ inner\ '''@type@'''\ to\ '''@var@''',\ and\ the\ inner\ \[\[proc_template\]\]\ expands\ both\ '''@var@'''s\ to\ '''name''',\ resulting\ in\ '''proc\ name\ \{\{method\ \"\"\}\ args\}\ \{upvar\ name\ self\;\ name\ self\ \$method\ \$args\}'''.\ \ Bad!\n\nDoes\ anyone\ have\ any\ suggestions\ for\ how\ to\ make\ this\ safe?\n\n----\n\nMethod\ inheritance\ (even\ multiple)\ can\ be\ had\ cheaply\ if\ the\ methods\ to\ be\ inherited\ are\ spliced\ in\ after\ the\ ''@methods''\ above.\ The\ switch\ might\ sometimes\ run\ longer,\ but\ every\ method\ not\ defined\ for\ your\ type\ would\ fall\ through\ to\ the\ first\ inherited\ method\ of\ same\ name.\n\n<<categories>>\ Object\ Orientation\ |\ Arts\ and\ crafts\ of\ Tcl-Tk\ programming regexp2} CALL {my render Gadgets \[Richard\ Suchenwirth\]\ --\ I\ have\ toyed\ with\ the\ gadget\ concept\ every\ now\ and\ then\ for\ years\ now\ (see\ \[tally:\ a\ string\ counter\ gadget\]\ or\ \[A\ matrix\ gadget\]),\ but\ here's\ a\ generalized\ approach.\ See\ also\ \[LOST\]\ for\ Larry\ Smith's\ extension\ to\ that..\ and\ \[On\ Things\]\ for\ a\ more\ radical\ typeless\ approach.\n\nI\ call\ gadgets\ \"poor\ man's\ objects\"\ -\ basically\ they\ are\ a\ variable\ (string,\ list\ or\ array)\ and\ a\ proc,\ both\ with\ the\ same\ name.\ The\ proc\ is\ renamed\ away\ when\ the\ variable\ dies.\ No\ inheritance\ (yet),\ no\ namespaces\ involved,\ but\ they\ offer\ a\ slick\ Tk-like\ API\ where\ you\ call\ the\ gadget's\ name\ with\ a\ minor\ command\ (method\ name)\ and\ possibly\ other\ parameters.\ \n\nFirst,\ a\ look\ at\ the\ generalized\ API.\ You\ can\ specify\ a\ gadget\ type\ with\ methods,\ in\ which\ you\ can\ refer\ to\ 'args'\ for\ the\ method's\ arguments\ (parse'em\ yourself\ \;-)\ and\ 'self'\ for\ the\ variable\ itself,\ like\ this:\n\n======\ngadget\ type\ number\ \{\n\ \ \ =\ \ \ \ \ \{set\ self\ \[expr\ \$args\]\}\n\ \ \ ++\ \ \ \ \{set\ self\ \[expr\ \$self+1\]\}\n\ \ \ round\ \{set\ self\ \[expr\ round(\$self)\]\}\ \n\ \ \ sqrt\ \ \{expr\ sqrt(\$self)\}\ \n\}\ngadget\ type\ int\ \{\n\ \ \ =\ \ \{set\ self\ \[expr\ round(\$args)\]\}\n\ \ \ ++\ \{incr\ self\}\n\}\ngadget\ type\ Array\ \{\n\ \ \ =\ -\ +=\ \{eval\ array\ set\ self\ \$args\ \}\n\ \ \ -=\ \ \ \ \ \{catch\ \{unset\ self(\$args)\}\}\n\ \ \ @\ \ \ \ \ \ \{set\ self(\$args)\}\n\ \ \ empty\ \ \{expr\ \[array\ size\ self\]==0\}\n\ \ \ names\ \ \{array\ names\ self\}\n\ \ \ \{\}\ \ \ \ \ \{array\ get\ self\}\n\}\ngadget\ type\ List\ \{\n\ \ \ =\ \ \ \ \ \ \{eval\ set\ self\ \$args\}\n\ \ \ +=\ \ \ \ \ \{lappend\ self\ \$args\}\n\ \ \ @\ \ \ \ \ \ \{lindex\ \$self\ \$args\}\n\ \ \ empty\ \ \{expr\ \[llength\ \$self\]==0\}\n\ \ \ sort\ \ \ \{lsort\ \$self\}\n\ \ \ length\ \{llength\ \$self\}\n\}\ngadget\ type\ File\ \{\n\ \ =\ \ \ \ \ \{set\ self\ \[eval\ open\ \$args\]\}\n\ \ >>\ \ \ \ \{upvar\ \$args\ var\;\ expr\ \[gets\ \$self\ var\]+1\}\n\ \ <<\ \ \ \ \{puts\ \$self\ \$args\}\n\ \ eof\ \ \ \{eof\ \$self\}\n\ \ open?\ \{expr\ !\[catch\ \{seek\ \$self\ 0\ current\}\]\}\n\ \ close\ \{close\ \$self\}\ \n\}\n======\nFor\ a\ defined\ gadget\ type,\ you\ can\ call\ a\ \"constructor\"\ with\ a\ name,\ and\ possibly\ an\ initialization:\n\n=====\nnumber\ N\ =\ 1.5\nArray\ A\nList\ L\ =\ \{foo\ bar\}\n======\n\nFor\ a\ \"destructor\",\ we\ just\ reuse\ the\ good\ old\ ''unset''\ wheel.\n\nNow\ you\ can\ use\ these\ variables\ or\ procs\ as\ you\ wish,\ with\ the\ addition\ that\ calling\ a\ (non-array)\ gadget\ proc\ without\ arguments\ returns\ its\ value,\ so\ \[\[N\]\]\ is\ a\ new\ alternative\ to\ \$N\ and\ \[\[set\ N\]\]:\n\n======\nN\ =\ \[N\]\ *\ \$N\ \ \ \ \ \ \ \ ->\ 2.25\ (just\ for\ the\ fun\ of\ it\ \;)\nset\ A(cat)\ Katze\ \ \ \ ->\ Katze\nA\ names\ \ \ \ \ \ \ \ \ \ \ \ \ ->\ cat\nL\ +=\ grill\nL\ =\ \[L\ sort\]\nputs\ \"\[L\]\ has\ \[L\ length\]\ elements,\ second\ is\ \[L\ @\ 1\]\"\n->\ bar\ foo\ grill\ has\ 3\ elements,\ second\ is\ foo\nFile\ F\ =\ gadget.tcl\nint\ i\ =\ 1\nwhile\ \{\[F\ >>\ line\]\}\ \{\n\ \ \ \ puts\ \[i\]:\$line\n\ \ \ \ i\ ++\n\}\nF\ close\n======\n\nYes,\ this\ is\ still\ Tcl,\ and\ no,\ it's\ not\ like\ in\ the\ book.\ You\ can\ adjust\ the\ language\ pretty\ much\ to\ your\ likings\ via\ the\ method\ names.\nArithmetic\ assignments\ look\ almost\ like\ all\ the\ world\ expects\ them\ to\ look\ (cf.\ \[Radical\ language\ modification\],\ where\ I\ tried\ the\ same\ goal\ with\ the\ unknown\ command),\ and\ by\ pressing\ the\ assigned\ value\ through\ expr\ in\ the\ \"number\ =\"\ or\ \"int\ =\"\ method,\ some\ typechecking\ is\ introduced.\ \n\nThe\ polymorphism\ (same\ method\ names\ for\ different\ types)\ allows\ some\ hiding\ of\ internal\ quirks,\ e.g.\ now\ you\ can\ increment\ a\ ''double''\ like\ an\ ''int''\ with\ ++,\ by\ just\ adding\ 1\ to\ it\ resp.\ calling\ incr.\ Notice\ also\ the\ polymorphism\ of\ +=\ for\ lists\ vs.\ arrays:\ append\ an\ element,\ or\ set\ a\ key-value\ pair.\n\nFor\ introspection,\ you\ can\ get\ the\ types\ and\ names\ defined,\ and\ each\ gadget\ tells\ his\ type\ if\ asked:\n\n======\ngadget\ types\ \ \ \ \ ->\ number\ int\ Array\ List\ File\ngadget\ names\ \ \ \ \ ->\ N\ A\ L\ F\nN\ type\ \ \ \ \ \ \ \ \ \ \ ->\ number\n======\n\nBook-keeping\ of\ names\ and\ types\ is\ done\ not\ with\ global\ variables,\ but\ with\ procs\ whose\ bodies\ are\ rewritten\ when\ needed.\ The\ calls\ to\ ''proc\ gadget:names''\ show\ how\ that's\ done:\ start\ with\ a\ argumentless\ list\ command,\ append\ a\ new\ name\ on\ gadget\ creation,\ lreplace\ the\ name\ out\ on\ gadget\ destruction.\n\nOK,\ so\ here's\ the\ code\ that\ does\ that\ (not\ very\ long,\ but\ not\ the\ easiest\ reading\ either\ -\ after\ all\ you\ write\ a\ proc\ that\ writes\ a\ proc\ that\ writes\ a\ proc\ \;-):\nThe\ switch\ line\ containing\ 'type'\ did\ not\ work\ on\ my\ system:\ adding\ eval\ worked\ like\ a\ charm.\ \ Has\ there\ been\ a\ change\ in\ how\ the\ switch\ command\ works\ since\ 2002?\ --\ Jim\ Hinds\n\n======\nproc\ gadget\ \{cmd\ args\}\ \{\n\ \ \ \ switch\ --\ \$cmd\ \{\n\ \ \ \ \ \ \ \ names\ \ \ \{gadget:names\}\n\ \ \ \ \ \ \ \ type\ \ \ \ \{gadget:type\ \$args\ \;\ #\ This\ command\ needed\ eval\ as\ in\ \{eval\ gadget:type\ \$args\}\ JH\ \ \}\n\ \ \ \ \ \ \ \ types\ \ \ \{gadget:types\}\n\ \ \ \ \ \ \ \ default\ \{return\ -code\ error\ \"\$cmd?\ should\ be\ name,\ type,\ or\ types\"\}\n\ \ \ \ \}\n\}\nproc\ gadget:types\ \{\}\ \{list\}\nproc\ gadget:names\ \{\}\ \{list\}\n\nproc\ gadget:type\ \{type\ methods\}\ \{\n\ \ \ \ if\ \{\[info\ commands\ \$type\]!=\"\"\}\ \{\n\ \ \ \ \ \ \ \ return\ -code\ error\ \"type\ \$type\ redefines\ existing\ command\"\n\ \ \ \ \}\n\ \ \ \ proc\ gadget:types\ \{\}\ \{concat\ \[info\ body\ gadget:types\]\ \$type\}\n\ \ \ \ set\ template\ \{\n\ \ \ \ \ \ \ \ proc\ @type@\ \{name\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$name==\"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ name\ \[lindex\ \$args\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ upvar\ 2\ \$name\ self\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rest\ \[lindex\ \$args\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cmd\ \ \[lindex\ \$rest\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ args\ \[lrange\ \$rest\ 1\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ --\ \$cmd\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ type\ \{return\ @type@\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ @methods@\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{\}\ \{set\ self\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ default\ \{return\ -code\ error\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\$cmd?\ Should\ be\ one\ of\ \[join\ \[list\ type\ @cmds@\]\]\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ commands\ \$name\]!=\"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"gadget\ \$name\ redefines\ existing\ command\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uplevel\ trace\ variable\ \$name\ u\ gadget:unset\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ proc\ gadget:names\ \{\}\ \{concat\ \[info\ body\ gadget:names\]\ \$name\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ proc\ \$name\ \{args\}\ \"@type@\ \{\}\ \$name\ \\\$args\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \[llength\ \$args\]\ \{uplevel\ \ \$name\ \$args\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ cmds\ \[list\]\n\ \ \ \ foreach\ \{cmd\ -\}\ \$methods\ \{lappend\ cmds\ \$cmd\}\n\ \ \ \ regsub\ -all\ @cmds@\ \ \ \ \$template\ \$cmds\ \ \ \ template\n\ \ \ \ regsub\ -all\ @type@\ \ \ \ \$template\ \$type\ \ \ \ template\n\ \ \ \ regsub\ -all\ @methods@\ \$template\ \$methods\ template\n\ \ \ \ eval\ \$template\n\ \ \ \ set\ type\n\}\n\nproc\ gadget:unset\ \{name\ el\ -\}\ \{\n\ \ \ \ if\ \{\$el==\"\"\}\ \{\n\ \ \ \ \ \ \ \ rename\ \$name\ \"\"\n\ \ \ \ \ \ \ \ set\ names\ \[info\ body\ gadget:names\]\n\ \ \ \ \ \ \ \ set\ where\ \[lsearch\ \$names\ \$name\]\n\ \ \ \ \ \ \ \ proc\ gadget:names\ \{\}\ \[lreplace\ \$names\ \$where\ \$where\]\n\ \ \ \ \}\ \ \n\}\n======\n\n'''Notes''':\ Gadgets\ can\ be\ passed\ by\ name\ in\ proc\ calls,\ where\ you\ either\ reuse\ the\ same\ name,\ or\ register\ the\ upvar\ variable:\n\n======\nupvar\ \$name\ \$name\ \;#\ or:\nupvar\ \$name\ var\;\ \[\$name\ type\]\ var\n======\n\nAs\ their\ procs\ are\ (of\ course)\ global,\ gadget\ names\ must\ be\ unique\ and\ may\ not\ use\ existing\ command\ (C\ or\ Tcl)\ names.\ This\ prevents\ one\ from\ accidentally\ rewriting\ \"set\"\ or\ other\ Tcl\ essentials.\ Drawback:\ gadgets\ with\ same\ name\ cannot\ be\ used\ in\ recursive\ procs.\n\n----\n\n\ \ \ *\ Shorter\ and\ Sweeter:\n\n\[Larry\ Smith\]\ (mailto:larry(...at\ sign...)smith-house.org)\ reverse-engineered\ an\ example\ I\ put\ on\ comp.lang.tcl\ and\ came\ to\ this\ beautiful\ short\ solution:\n\n======\nproc\ gadget\ \{\ unused\ type\ methods\ \}\ \{\n\ \ \ \ set\ typeproc\ \{\n\ \ \ \ \ \ \ \ set\ typeproc\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ @var\ self\n\ \ \ \ \ \ \ \ \ \ \ \ @type\ self\ \$method\ \$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ upvar\ \$var\ self\n\ \ \ \ \ \ \ \ if\ \{\ \"\$method\"\ ==\ \"\"\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$self\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ switch\ \$method\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ @methods\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ regsub\ @var\ \$typeproc\ \$var\ typeproc\n\ \ \ \ \ \ \ \ proc\ \$var\ \{\ \{\ method\ \"\"\ \}\ args\ \}\ \$typeproc\n\ \ \ \ \}\n\ \ \ \ regsub\ @type\ \$typeproc\ \$type\ typeproc\n\ \ \ \ regsub\ @methods\ \$typeproc\ \$methods\ typeproc\n\ \ \ \ proc\ \$type\ \{\ var\ method\ args\ \}\ \$typeproc\n\}\n======\n\nI\ find\ it\ more\ legible,\ though,\ if\ all\ four\ mentions\ of\ ''typeproc''\ inside\ the\ first\ ''set\ typeproc\ ..''\ are\ replaced\ by\ ''instproc'',\ as\ that\ is\ dealing\ with\ the\ instance\ proc\ anyway.\ -\ RS\n\n\[AMG\]:\ The\ \[\[\[regsub\]\]\]s\ can\ be\ replaced\ with\ \[\[\[string\ map\]\]\]s:\n\n======\nproc\ \$var\ \{\{method\ \"\"\}\ args\}\ \[string\ map\ \[list\ @var\ \$var\]\ \$typeproc\]\nproc\ \$type\ \{var\ method\ args\}\ \[string\ map\ \[list\ @type\ \$type\ @methods\ \$methods\]\ \$typeproc\]\n======\n\nWhoa,\ to\ avoid\ unwanted\ expansion,\ better\ put\ an\ extra\ level\ of\ listiness\ in\ there:\n\n======\n\[string\ map\ \[list\ @var\ \[list\ \$var\]\]\ \$typeproc\]\n======\n\nYou\ can\ even\ lose\ the\ \$typeproc\ variables,\ instead\ directly\ including\ the\ template.\ \ To\ make\ things\ easier\ still,\ make\ a\ helper\ procedure\ to\ do\ the\ string\ mapping.\ \ Yet\ more:\ make\ that\ helper\ procedure\ itself\ make\ procedures!\n\n======\nproc\ proc_template\ \{name\ lazy_args\ eager_args\ body\}\ \{\n\ \ \ \ set\ map\ \[list\]\n\ \ \ \ foreach\ varname\ \$eager_args\ \{\n\ \ \ \ \ \ \ \ upvar\ 1\ \$varname\ var\n\ \ \ \ \ \ \ \ lappend\ map\ @\$varname@\ \[list\ \$var\]\n\ \ \ \ \}\n\ \ \ \ proc\ \$name\ \$lazy_args\ \[string\ map\ \$map\ \$body\]\n\}\n\nproc\ gadget\ \{unused\ type\ methods\}\ \{\n\ \ \ \ proc_template\ \$type\ \{var\ method\ args\}\ \{type\ methods\}\ \{\n\ \ \ \ \ \ \ \ upvar\ \$var\ self\n\ \ \ \ \ \ \ \ if\ \{\$method\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$self\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ switch\ \$method\ @methods@\n\ \ \ \ \ \ \ \ proc_template\ \$var\ \{\{method\ \"\"\}\ args\}\ \{var\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ @var@\ self\n\ \ \ \ \ \ \ \ \ \ \ \ @type@\ self\ \$method\ \$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n======\n\nThere's\ a\ pitfall\ here,\ though:\n\n======none\ngadget\ type\ @var@\ \{=\ \{set\ self\ \[expr\ \$args\]\}\}\n@var@\ name\ =\ 5\nname\nERROR:\ too\ many\ nested\ evaluations\n======\n\nThe\ outer\ \[\[proc_template\]\]\ expands\ the\ inner\ '''@type@'''\ to\ '''@var@''',\ and\ the\ inner\ \[\[proc_template\]\]\ expands\ both\ '''@var@'''s\ to\ '''name''',\ resulting\ in\ '''proc\ name\ \{\{method\ \"\"\}\ args\}\ \{upvar\ name\ self\;\ name\ self\ \$method\ \$args\}'''.\ \ Bad!\n\nDoes\ anyone\ have\ any\ suggestions\ for\ how\ to\ make\ this\ safe?\n\n----\n\nMethod\ inheritance\ (even\ multiple)\ can\ be\ had\ cheaply\ if\ the\ methods\ to\ be\ inherited\ are\ spliced\ in\ after\ the\ ''@methods''\ above.\ The\ switch\ might\ sometimes\ run\ longer,\ but\ every\ method\ not\ defined\ for\ your\ type\ would\ fall\ through\ to\ the\ first\ inherited\ method\ of\ same\ name.\n\n<<categories>>\ Object\ Orientation\ |\ Arts\ and\ crafts\ of\ Tcl-Tk\ programming} CALL {my revision Gadgets} CALL {::oo::Obj930588 process revision/Gadgets} CALL {::oo::Obj930586 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