Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/The+Anatomy+of+an+Object+System?V=0
QUERY_STRINGV=0
CONTENT_TYPE
DOCUMENT_URI/revision/The+Anatomy+of+an+Object+System
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR172.70.100.89
REMOTE_PORT59612
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR18.221.72.217
HTTP_CF_RAY88ce4481ad0d8f49-ORD
HTTP_X_FORWARDED_PROTOhttps
HTTP_CF_VISITOR{"scheme":"https"}
HTTP_ACCEPT*/*
HTTP_USER_AGENTMozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; [email protected])
HTTP_REFERERhttp://wiki.tcl.tk./revision/The+Anatomy+of+an+Object+System?V=0
HTTP_CF_CONNECTING_IP18.221.72.217
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 {The Anatomy of an Object System} if\ 0\ \{\n\n\[PYK\]\ 2016-09-06:\ \ \[namespace%|%namespaces\]\ had\ their\ genesis\ in\ a\nconverstation\ at\ a\ Tcl\ conference\ about\ what\ a\ common\ foundation\ for\ all\ the\nexisting\ Tcl\ object\ systems\ would\ look\ like.\ \ Since\ then\ (well,\ and\ long\ before\nthen),\ Tcl\ programmers\ have\ amused\ themselves\ with\ attempts\ to\ create\ the\ most\nminimal\ and\ \[elegance%|%elegant\]\ object\ systems.\ \ An\ object\ is\ a\ collection\ of\nrelated\ data,\ along\ with\ a\ set\ of\ commands\ that\ operate\ on\ that\ data.\ \ An\n\[object\ orientation%|%object\ system\]\ exists\ to\ facilitate\ the\ composition\ and\noperation\ of\ such\ objects.\ \ \[wjd%|%Will\ Duquette\]\ once\ published\n\[http://www.wjduquette.com/tcl/objects.html%|%Creating\ Object\ Commands\],\ which\nI\ found\ quite\ informative\ somewhere\ along\ my\ way\ into\ Tcl,\ and\ from\ there\ have\ndistilled\ into\ an\ updated\ take\ on\ how\ to\ create\ such\ systems.\ \ This\ walkthrough\nserves\ both\ as\ a\ tutorial\ on\ creating\ a\ particular\ object\ system,\ and\ as\ an\nintroduction\ to\ the\ facilities\ provided\ by\ `\[namespace\]`.\n\nThe\ primary\ principles\ of\ the\ system\ presented\ below\ are:\n\n\ \ \ *\ A\ \[namespace\ ensemble\]\ is\ the\ name\ of\ the\ object,\ as\ well\ as\ of\ the\ namespace\ that\ represents\ the\ object.\n\n\ \ \ *\ Each\ object\ command\ is\ registered\ in\ the\ \[namespace\ ensemble\]\ map\ such\ that\ a\ call\ to\ object\ command\ is\ a\ call\ to\ a\ dispatcher\ that\ resolves\ and\ calls\ the\ actual\ command,\ passing\ it\ the\ name\ of\ the\ current\ object.\n\n\ \ \ *\ namespaces\ that\ contribute\ commands\ to\ the\ object\ are\ accessed\ through\ the\ \[namespace\ path\]\ of\ the\ object.\ \n\n\nGiven\ the\ features\ of\ `\[namespace\]`,\ one\ question\ is\ particularly\ vexing:\ How\nto\ arrange\ for\ access\ to\ the\ current\ object\ from\ within\ an\ object\ command.\nIdeally,\ there\ would\ be\ a\ `namespace\ ensemble\ current`,\ which\ returned\ the\ name\nof\ the\ closest\ active\ namespace\ ensemble.\ \ One\ might\ simply\ put\ the\ object\ncommands\ in\ the\ namespace\ representing\ the\ object,\ which\ would\ allow\ access\ to\nthe\ object\ data\ using\ standard\ commands\ like\ `\[variable\]`,\ but\ that\ requires\nduplicating\ commands\ for\ each\ object,\ which\ is\ no\ fun.\ \ This\ leaves\ either\ the\nensemble\ map\ or\ the\ `\[namespace\ unknown\]`\ mechanism\ as\ alternatives.\n\nTo\ illustrate\ how\ to\ put\ all\ the\ pieces\ of\ the\ object\ system\ together.\ \ This\narticle\ walks\ throught\ the\ implementation\ of\ implement\ a\ timer.\ \ Most\ of\ the\nsystem\ is\ implemented\ in\ the\ command\ that\ creates\ the\ objects.\ `\$_`\ is\ the\ name\nof\ the\ object.\ \ The\ command\ to\ create\ new\ timers\ is\ a\ regular\ procedure,\ not\ a\nnamespace\ ensemble:\n======\n\}\n\nnamespace\ eval\ timer\ \{\n\n\ \ \ \ proc\ \[namespace\ current\]\ name\ \{\n\ \ \ \ \ \ \ \ set\ _\ \[uplevel\ 1\ \[list\ namespace\ eval\ \$name\ \{namespace\ current\}\]\]\n\ \ \ \ \ \ \ \ namespace\ eval\ \$_\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ ::apply\ \[list\ \{\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ action\ \{elapsed\ lap\ running\ start\ stop\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ map\ \$action\ \[list\ ::apply\ \[list\ \{_\ action\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \$action\ \$_\ \{*\}\$args\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \[namespace\ current\]\]\ \[namespace\ current\]\ \$action\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ ensemble\ create\ -map\ \$map\ \n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \[namespace\ current\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Initialize\ the\ object\ data\n\ \ \ \ \ \ \ \ \ \ \ \ variable\ elapsed\ \[expr\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ variable\ running\ \[expr\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ variable\ start\ \[expr\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ current\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ namespace\ eval\ \$name\ \[list\ namespace\ path\ \[list\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ current\]::\[namespace\ tail\ \[lindex\ \[info\ level\ 0\]\ 0\]\]\ \{*\}\[namespace\ eval\ \$name\ \{namespace\ path\}\]\]\]\n\ \ \ \ \ \ \ \ return\ \$_\n\ \ \ \ \}\n\n\ \ \ \ #\ \[start\],\ \[stop\],\ \[elapsed\],\ and\ \[running\]\ will\ live\ in\ this\ namespace\ as\ well\n\n\}\n\nif\ 0\ \{\n======\n\n`\[apply\]`\ and\ `\[tailcall\]`\ are\ used\ to\ avoid\ adding\ an\ extra\ level\ to\ the\ninterpreter\ when\ the\ subcommand\ is\ called.\ \ If\ `\[namespace\ code\]`\ didn't\ add\nthat\ level,\ the\ above\ could\ be\ written\ like\ this\ instead:\n\n======\n#\ This\ code\ is\ a\ non-working\ example\nif\ 0\ \{\n\ \ \ \ namespace\ ensemble\ create\ -map\ \ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ elapsed\ \[namespace\ code\ elapsed\ \[namespace\ current\]\ \{*\}\$args\]\ \\\n\ \ \ \ \ \ \ \ running\ \[namespace\ code\ running\ \[namespace\ current\]\ \{*\}\$args\]\ \\\n\ \ \ \ \ \ \ \ start\ \[namespace\ code\ start\ \[namespace\ current\]\ \{*\}\$args\]\ \\\n\ \ \ \ \ \ \ \ stop\ \[namespace\ code\ stop\ \[namespace\ current\]\ \{*\}\$args\]\ \\\n\ \ \ \ \]\n\}\n======\n\nTo\ create\ a\ new\ timer:\n\n======\n\}\ntimer\ timer1\nif\ 0\ \{\n======\n\nThe\ next\ step\ is\ to\ implement\ the\ commands.\ \ Although\ `timer1`\ already\ exists\nas\ these\ commands\ are\ created,\ they\ implement\ the\ functionality\ of\ `timer1`:\n======\n\}\n\nnamespace\ eval\ timer\ \{\n\n\ \ \ \ proc\ lap\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ elapsed\ elapsed\ start\ start\n\ \ \ \ \ \ \ \ expr\ \{\[clock\ clicks\]\ -\ \$start\}\n\ \ \ \ \}\n\n\ \ \ \ proc\ elapsed\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ elapsed\ elapsed\n\ \ \ \ \ \ \ \ \$_\ stop\n\ \ \ \ \ \ \ \ \$_\ start\n\ \ \ \ \ \ \ \ return\ \$elapsed\n\ \ \ \ \}\n\n\ \ \ \ proc\ running\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ running\ running\n\ \ \ \ \ \ \ \ return\ \$running\n\ \ \ \ \}\n\n\ \ \ \ proc\ stop\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ elapsed\ elapsed\ running\ running\ start\ start\n\ \ \ \ \ \ \ \ set\ running\ \[expr\ 0\]\n\ \ \ \ \ \ \ \ set\ elapsed\ \[expr\ \{\$elapsed\ +\ \[\$_\ lap\]\}\]\ \n\ \ \ \ \ \ \ \ set\ start\ \[expr\ -1\]\n\ \ \ \ \ \ \ \ return\ \$elapsed\n\ \ \ \ \}\n\n\ \ \ \ proc\ start\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ running\ running\ start\ start\n\ \ \ \ \ \ \ \ if\ \{\$start\ ==\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ start\ \[clock\ clicks\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\nif\ 0\ \{\n======\n\n`\[namespace\ upvar\]`\ is\ used\ to\ access\ object\ data.\ \ Here\ are\ the\ remaining\ commands:\n\nNow,\ to\ test\ it\ out:\n\n======\n\}\ntimer1\ start\nafter\ 2000\nputs\ \[timer1\ elapsed\]\n\nif\ 0\ \{\n======\n\nDeriving\ another\ kind\ of\ timer\ from\ this\ one\ is\ a\ matter\ of\ manipulating\ the\nmap\ and\ the\ `\[namespace\ path\]`\ in\ the\ new\ timer\ creator:\n\n======\n\}\nnamespace\ eval\ vartimer\ \{\n\ \ \ \ proc\ \[namespace\ current\]\ name\ \{\n\ \ \ \ \ \ \ \ set\ _\ \[uplevel\ 1\ \[list\ \[namespace\ which\ timer\]\ \$name\]\]\n\ \ \ \ \ \ \ \ namespace\ eval\ \$_\ \[list\ namespace\ path\ \[list\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ current\]::\[namespace\ tail\ \[lindex\ \[info\ level\ 0\]\ 0\]\]\ \{*\}\[namespace\ eval\ \$_\ \{namespace\ path\}\]\]\]\n\ \ \ \ \ \ \ \ set\ map\ \[namespace\ ensemble\ configure\ \$_\ -map\]\n\ \ \ \ \ \ \ \ foreach\ action\ \{faster\ slower\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ map\ \$action\ \[list\ ::apply\ \[list\ \{_\ action\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \$action\ \$_\ \{*\}\$args\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \$_\]\ \$_\ \$action\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ namespace\ ensemble\ configure\ \$_\ -map\ \$map\n\ \ \ \ \ \ \ \ namespace\ eval\ \$_\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ variable\ factor\ 1.0\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$_\n\ \ \ \ \}\n\n\}\nnamespace\ eval\ vartimer\ \{\n\ \ \ \ proc\ faster\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ factor\ factor\n\ \ \ \ \ \ \ \ set\ factor\ \[expr\ \{\$factor\ *\ 1.25\}\]\n\ \ \ \ \}\n\ \ \ \ proc\ slower\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ factor\ factor\n\ \ \ \ \ \ \ \ set\ factor\ \[expr\ \{\$factor\ *\ .25\}\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ lap\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ factor\ factor\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ elapsed\ upelapsed\n\ \ \ \ \ \ \ \ set\ lap\ \[\[namespace\ which\ timer\]::lap\ \$_\]\n\ \ \ \ \ \ \ \ set\ upelapsed\ \[expr\ \{\$upelapsed\ +\ (\$lap\ *\ \$factor)\}\]\n\ \ \ \ \}\n\}\n\n\nif\ 0\ \{\n======\n\nNow\ to\ try\ it\ out:\n\n======\n\}\nvartimer\ timer2\ntimer2\ faster\ntimer2\ faster\ntimer2\ start\nafter\ 2000\nputs\ \[timer2\ elapsed\]\n\nif\ 0\ \{\n======\n\nNow\ comes\ the\ fun\ part:\ \ Taking\ the\ functionality\ sketched\ out\ above\ and\npackaging\ it\ into\ a\ general\ system\ that's\ convenient\ to\ use.\ \ This\ increased\nthe\ complexity\ of\ the\ implementation,\ of\ course,\ but\ will\ make\ it\ easier\ to\ncompose\ and\ manage\ objects.\ \ To\ make\ something\ that's\ friendly\ to\ use,\ as\ well\nas\ more\ orthogonal,\ a\ few\ things\ will\ have\ to\ change.\ \ First,\ the\ basic\nfunctionality\ is\ encapsulated\ into\ a\ primordial\ object,\ the\ thing\ from\ which\nall\ other\ objects\ spring.\ \ This\ object\ will\ be\ a\ `\[namespace\ ensemble\]`,\ so\ it\nwill\ no\ longer\ be\ possible\ to\ call\ it\ directly\ to\ create\ new\ objects.\ \ Instead,\nit\ will\ have\ an\ object\ command,\ `new`,\ for\ that\ purpose.\ \ The\ two\ most\ basic\nthings\ an\ object\ should\ be\ able\ to\ do\ is\ configure\ what\ it\ is,\ and\ what\ it\ndoes.\ \ Thus,\ the\ next\ two\ commands\ to\ be\ implemented\ are\ `is`\ and\ `does`.\n\nBootstrapping\ the\ first\ object\ in\ the\ known\ universe\ is\ always\ a\ little\nproblematic,\ but\ in\ this\ case,\ it's\ not\ too\ bad,\ just\ a\ matter\ of\ calling\ a\ncouple\ of\ commands\ directly\ instead\ of\ calling\ them\ through\ the\ object\ name,\ as\nall\ other\ objects\ will\ do.\n\n======\n\}\n\nnamespace\ eval\ object\ \{\n\n\ \ \ \ proc\ is\ \{_\ what\}\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[string\ match\ ::*\ \$what\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ what\ \[uplevel\ 1\ \[list\ namespace\ which\ \$what\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ _path\ \[namespace\ eval\ \$_\ \{namespace\ path\}\]\n\ \ \ \ \ \ \ \ if\ \{\$what\ ni\ \$_path\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ eval\ \$_\ \[list\ namespace\ path\ \[list\ \$what\ \{*\}\$_path\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ map_orig\ \[namespace\ ensemble\ configure\ \$_\ -map\]\n\ \ \ \ \ \ \ \ set\ map_add\ \[namespace\ ensemble\ configure\ \$what\ -map\]\n\ \ \ \ \ \ \ \ namespace\ ensemble\ configure\ \$_\ -map\ \[dict\ merge\ \$map_add\ \$map_orig\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ does\ \{_\ args\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ map\ \[namespace\ ensemble\ configure\ \$_\ -map\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ what\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$what\]\ ==\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ what\ what\ target\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ target\ \$what\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ map\ \$what\ \[list\ ::apply\ \[list\ \{_\ target\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \$target\ \$_\ \{*\}\$args\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \$_\]\ \$_\ \$target\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ ensemble\ configure\ \$_\ -map\ \$map\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ keys\ \[namespace\ ensemble\ configure\ \$_\ -map\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ init\ \{_\ args\}\ \{\}\n\n\ \ \ \ proc\ new\ \{_\ name\}\ \{\n\ \ \ \ \ \ \ \ set\ name\ \[uplevel\ 1\ \[::list\ namespace\ eval\ \$name\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ ::namespace\ ensemble\ create\n\ \ \ \ \ \ \ \ \ \ \ \ ::namespace\ current\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \ \ \ \ set\ map\ \{\}\n\ \ \ \ \ \ \ \ foreach\ \{cmd\ target\}\ \[namespace\ ensemble\ configure\ \$_\ -map\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ args\ \[lassign\ \$target\ apply\ function\ arg1\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ function\ \[lreplace\ \$function\ 2\ 2\ \$name\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ target\ \[list\ \$apply\ \$function\ \$name\ \{*\}\$args\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ map\ \$cmd\ \$target\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ namespace\ ensemble\ configure\ \$name\ -map\ \$map\n\ \ \ \ \ \ \ \ namespace\ eval\ \$name\ \[list\ namespace\ path\ \[namespace\ eval\ \$_\ \{namespace\ path\}\]\]\n\ \ \ \ \ \ \ \ \$name\ is\ \$_\n\ \ \ \ \ \ \ \ \$name\ does\ init\n\ \ \ \ \ \ \ \ \$name\ init\n\ \ \ \ \ \ \ \ return\ \$name\n\ \ \ \ \}\n\n\ \ \ \ #\ bootstrap\ the\ system\n\ \ \ \ namespace\ ensemble\ create\n\ \ \ \ does\ \[namespace\ current\]\ is\n\ \ \ \ does\ \[namespace\ current\]\ does\n\ \ \ \ \[namespace\ current\]\ is\ \[namespace\ current\]\n\ \ \ \ \[namespace\ current\]\ does\ new\n\}\n\nif\ 0\ \{\n======\n\nLet's\ make\ an\ command\ to\ make\ it\ more\ convenient\ to\ evaluate\ scripts\ in\ the\nobject\ namespace:\n\n======\n\}\n\nnamespace\ eval\ object\ \{\n\ \ \ \ proc\ eval\ \{_\ args\}\ \{\n\ \ \ \ \ \ \ \ ::tailcall\ namespace\ eval\ \$_\ \[join\ \$args\]\n\ \ \ \ \}\n\}\nobject\ does\ eval\n\nif\ 0\ \{\n======\n\nMany\ object\ systems\ provide\ some\ way\ for\ an\ object\ command\ to\ call\ an\ object\ncommand\ by\ the\ same\ name\ in\ an\ ancestor\ object.\ \ Let's\ add\ one\ to\ the\ object.\nThe\ `\\0`\ namespace\ is\ just\ used\ as\ an\ empty\ namespace\ separate\ from\ the\ normal\nobject,\ that\ can\ be\ configured\ with\ the\ path\ of\ the\ object\ in\ order\ to\ look\ up\nthe\ next\ command.\ \ Since\ the\ path\ of\ an\ object\ may\ change\ dynamically,\ it's\nbest\ to\ grab\ that\ path\ and\ configure\ `\\0'\ with\ it\ just\ before\ the\ lookup.\n\n======\n\}\nnamespace\ eval\ object\ \{\n\ \ \ \ proc\ upcall\ \{_\ args\}\ \{\n\ \ \ \ \ \ \ \ set\ current\ \[uplevel\ 1\ \{namespace\ current\}\]\ \n\ \ \ \ \ \ \ \ set\ path\ \[namespace\ eval\ \$_\ \{namespace\ path\}\]\n\ \ \ \ \ \ \ \ while\ \{\[set\ idx\ \[lsearch\ -exact\ \$path\ \$current\]\]\ >=\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[lreplace\ \$path\ \$idx\ \$idx\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ namespace\ eval\ \\0\ \[list\ namespace\ path\ \$path\]\n\ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \{_\ cmd\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \$cmd\ \$_\ \{*\}\$args\n\ \ \ \ \ \ \ \ \}\ \[namespace\ current\]::\\0\]\ \$_\ \{*\}\$args\n\ \ \ \ \}\n\}\nobject\ does\ upcall\n\n\nif\ 0\ \{\n======\nNow\ that\ the\ primordial\ object\ exists,\ it\ can\ be\ used\ to\ create\ another\ object\nas\ the\ timer:\n======\n\}\n\n#rename\ timer\ \{\}\nobject\ new\ timer\ntimer\ does\ lap\ elapsed\ running\ start\ stop\n\nif\ 0\ \{\n======\n\nCreate\ a\ command\ to\ initialize\ the\ timer:\n\n======\n\}\n\n\ntimer\ eval\ \{\n\ \ \ \ proc\ init\ _\ \ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ elapsed\ elapsed\ running\ running\ start\ start\n\ \ \ \ \ \ \ \ set\ elapsed\ \[expr\ 0\]\n\ \ \ \ \ \ \ \ set\ running\ \[expr\ 0\]\n\ \ \ \ \ \ \ \ set\ start\ \[expr\ -1\]\n\ \ \ \ \ \ \ \ return\ \$_\n\ \ \ \ \}\n\}\n\n\ntimer\ new\ timer1\ntimer1\ start\nafter\ 2000\nputs\ \[timer1\ elapsed\]\n\nif\ 0\ \{\n======\n\nTo\ create\ a\ specialized\ timer,\ create\ a\ timer\ and\ then\ override\ the\ object\ncommands\ to\ as\ needed:\n\n======\n\}\n\ntimer\ new\ vartimer\nvartimer\ does\ faster\ slower\n\nvartimer\ eval\ \{\n\ \ \ \ proc\ init\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ factor\ factor\n\ \ \ \ \ \ \ \ \$_\ upcall\ init\n\ \ \ \ \ \ \ \ set\ factor\ 1.0\n\ \ \ \ \}\n\}\n\nvartimer\ new\ timer2\ntimer2\ faster\ntimer2\ faster\ntimer2\ start\nafter\ 2000\nputs\ \[timer2\ elapsed\]\n\nif\ 0\ \{\n======\n\nThat's\ it.\ \ The\ object\ system\ presented\ on\ this\ page\ has\ a\ sufficient\ feature\nset\ to\ use\ in\ real\ projects.\ \ \[ycl\ shelf\]\ is\ built\ on\ many\ of\ these\ techniques,\nand\ \ features\ more\ bells\ and\ whistles.\n\n======\n\n<<categories>>\ object\ orientation\n\} regexp2} CALL {my render {The Anatomy of an Object System} if\ 0\ \{\n\n\[PYK\]\ 2016-09-06:\ \ \[namespace%|%namespaces\]\ had\ their\ genesis\ in\ a\nconverstation\ at\ a\ Tcl\ conference\ about\ what\ a\ common\ foundation\ for\ all\ the\nexisting\ Tcl\ object\ systems\ would\ look\ like.\ \ Since\ then\ (well,\ and\ long\ before\nthen),\ Tcl\ programmers\ have\ amused\ themselves\ with\ attempts\ to\ create\ the\ most\nminimal\ and\ \[elegance%|%elegant\]\ object\ systems.\ \ An\ object\ is\ a\ collection\ of\nrelated\ data,\ along\ with\ a\ set\ of\ commands\ that\ operate\ on\ that\ data.\ \ An\n\[object\ orientation%|%object\ system\]\ exists\ to\ facilitate\ the\ composition\ and\noperation\ of\ such\ objects.\ \ \[wjd%|%Will\ Duquette\]\ once\ published\n\[http://www.wjduquette.com/tcl/objects.html%|%Creating\ Object\ Commands\],\ which\nI\ found\ quite\ informative\ somewhere\ along\ my\ way\ into\ Tcl,\ and\ from\ there\ have\ndistilled\ into\ an\ updated\ take\ on\ how\ to\ create\ such\ systems.\ \ This\ walkthrough\nserves\ both\ as\ a\ tutorial\ on\ creating\ a\ particular\ object\ system,\ and\ as\ an\nintroduction\ to\ the\ facilities\ provided\ by\ `\[namespace\]`.\n\nThe\ primary\ principles\ of\ the\ system\ presented\ below\ are:\n\n\ \ \ *\ A\ \[namespace\ ensemble\]\ is\ the\ name\ of\ the\ object,\ as\ well\ as\ of\ the\ namespace\ that\ represents\ the\ object.\n\n\ \ \ *\ Each\ object\ command\ is\ registered\ in\ the\ \[namespace\ ensemble\]\ map\ such\ that\ a\ call\ to\ object\ command\ is\ a\ call\ to\ a\ dispatcher\ that\ resolves\ and\ calls\ the\ actual\ command,\ passing\ it\ the\ name\ of\ the\ current\ object.\n\n\ \ \ *\ namespaces\ that\ contribute\ commands\ to\ the\ object\ are\ accessed\ through\ the\ \[namespace\ path\]\ of\ the\ object.\ \n\n\nGiven\ the\ features\ of\ `\[namespace\]`,\ one\ question\ is\ particularly\ vexing:\ How\nto\ arrange\ for\ access\ to\ the\ current\ object\ from\ within\ an\ object\ command.\nIdeally,\ there\ would\ be\ a\ `namespace\ ensemble\ current`,\ which\ returned\ the\ name\nof\ the\ closest\ active\ namespace\ ensemble.\ \ One\ might\ simply\ put\ the\ object\ncommands\ in\ the\ namespace\ representing\ the\ object,\ which\ would\ allow\ access\ to\nthe\ object\ data\ using\ standard\ commands\ like\ `\[variable\]`,\ but\ that\ requires\nduplicating\ commands\ for\ each\ object,\ which\ is\ no\ fun.\ \ This\ leaves\ either\ the\nensemble\ map\ or\ the\ `\[namespace\ unknown\]`\ mechanism\ as\ alternatives.\n\nTo\ illustrate\ how\ to\ put\ all\ the\ pieces\ of\ the\ object\ system\ together.\ \ This\narticle\ walks\ throught\ the\ implementation\ of\ implement\ a\ timer.\ \ Most\ of\ the\nsystem\ is\ implemented\ in\ the\ command\ that\ creates\ the\ objects.\ `\$_`\ is\ the\ name\nof\ the\ object.\ \ The\ command\ to\ create\ new\ timers\ is\ a\ regular\ procedure,\ not\ a\nnamespace\ ensemble:\n======\n\}\n\nnamespace\ eval\ timer\ \{\n\n\ \ \ \ proc\ \[namespace\ current\]\ name\ \{\n\ \ \ \ \ \ \ \ set\ _\ \[uplevel\ 1\ \[list\ namespace\ eval\ \$name\ \{namespace\ current\}\]\]\n\ \ \ \ \ \ \ \ namespace\ eval\ \$_\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ ::apply\ \[list\ \{\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ action\ \{elapsed\ lap\ running\ start\ stop\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ map\ \$action\ \[list\ ::apply\ \[list\ \{_\ action\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \$action\ \$_\ \{*\}\$args\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \[namespace\ current\]\]\ \[namespace\ current\]\ \$action\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ ensemble\ create\ -map\ \$map\ \n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \[namespace\ current\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Initialize\ the\ object\ data\n\ \ \ \ \ \ \ \ \ \ \ \ variable\ elapsed\ \[expr\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ variable\ running\ \[expr\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ variable\ start\ \[expr\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ current\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ namespace\ eval\ \$name\ \[list\ namespace\ path\ \[list\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ current\]::\[namespace\ tail\ \[lindex\ \[info\ level\ 0\]\ 0\]\]\ \{*\}\[namespace\ eval\ \$name\ \{namespace\ path\}\]\]\]\n\ \ \ \ \ \ \ \ return\ \$_\n\ \ \ \ \}\n\n\ \ \ \ #\ \[start\],\ \[stop\],\ \[elapsed\],\ and\ \[running\]\ will\ live\ in\ this\ namespace\ as\ well\n\n\}\n\nif\ 0\ \{\n======\n\n`\[apply\]`\ and\ `\[tailcall\]`\ are\ used\ to\ avoid\ adding\ an\ extra\ level\ to\ the\ninterpreter\ when\ the\ subcommand\ is\ called.\ \ If\ `\[namespace\ code\]`\ didn't\ add\nthat\ level,\ the\ above\ could\ be\ written\ like\ this\ instead:\n\n======\n#\ This\ code\ is\ a\ non-working\ example\nif\ 0\ \{\n\ \ \ \ namespace\ ensemble\ create\ -map\ \ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ elapsed\ \[namespace\ code\ elapsed\ \[namespace\ current\]\ \{*\}\$args\]\ \\\n\ \ \ \ \ \ \ \ running\ \[namespace\ code\ running\ \[namespace\ current\]\ \{*\}\$args\]\ \\\n\ \ \ \ \ \ \ \ start\ \[namespace\ code\ start\ \[namespace\ current\]\ \{*\}\$args\]\ \\\n\ \ \ \ \ \ \ \ stop\ \[namespace\ code\ stop\ \[namespace\ current\]\ \{*\}\$args\]\ \\\n\ \ \ \ \]\n\}\n======\n\nTo\ create\ a\ new\ timer:\n\n======\n\}\ntimer\ timer1\nif\ 0\ \{\n======\n\nThe\ next\ step\ is\ to\ implement\ the\ commands.\ \ Although\ `timer1`\ already\ exists\nas\ these\ commands\ are\ created,\ they\ implement\ the\ functionality\ of\ `timer1`:\n======\n\}\n\nnamespace\ eval\ timer\ \{\n\n\ \ \ \ proc\ lap\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ elapsed\ elapsed\ start\ start\n\ \ \ \ \ \ \ \ expr\ \{\[clock\ clicks\]\ -\ \$start\}\n\ \ \ \ \}\n\n\ \ \ \ proc\ elapsed\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ elapsed\ elapsed\n\ \ \ \ \ \ \ \ \$_\ stop\n\ \ \ \ \ \ \ \ \$_\ start\n\ \ \ \ \ \ \ \ return\ \$elapsed\n\ \ \ \ \}\n\n\ \ \ \ proc\ running\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ running\ running\n\ \ \ \ \ \ \ \ return\ \$running\n\ \ \ \ \}\n\n\ \ \ \ proc\ stop\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ elapsed\ elapsed\ running\ running\ start\ start\n\ \ \ \ \ \ \ \ set\ running\ \[expr\ 0\]\n\ \ \ \ \ \ \ \ set\ elapsed\ \[expr\ \{\$elapsed\ +\ \[\$_\ lap\]\}\]\ \n\ \ \ \ \ \ \ \ set\ start\ \[expr\ -1\]\n\ \ \ \ \ \ \ \ return\ \$elapsed\n\ \ \ \ \}\n\n\ \ \ \ proc\ start\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ running\ running\ start\ start\n\ \ \ \ \ \ \ \ if\ \{\$start\ ==\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ start\ \[clock\ clicks\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\nif\ 0\ \{\n======\n\n`\[namespace\ upvar\]`\ is\ used\ to\ access\ object\ data.\ \ Here\ are\ the\ remaining\ commands:\n\nNow,\ to\ test\ it\ out:\n\n======\n\}\ntimer1\ start\nafter\ 2000\nputs\ \[timer1\ elapsed\]\n\nif\ 0\ \{\n======\n\nDeriving\ another\ kind\ of\ timer\ from\ this\ one\ is\ a\ matter\ of\ manipulating\ the\nmap\ and\ the\ `\[namespace\ path\]`\ in\ the\ new\ timer\ creator:\n\n======\n\}\nnamespace\ eval\ vartimer\ \{\n\ \ \ \ proc\ \[namespace\ current\]\ name\ \{\n\ \ \ \ \ \ \ \ set\ _\ \[uplevel\ 1\ \[list\ \[namespace\ which\ timer\]\ \$name\]\]\n\ \ \ \ \ \ \ \ namespace\ eval\ \$_\ \[list\ namespace\ path\ \[list\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ current\]::\[namespace\ tail\ \[lindex\ \[info\ level\ 0\]\ 0\]\]\ \{*\}\[namespace\ eval\ \$_\ \{namespace\ path\}\]\]\]\n\ \ \ \ \ \ \ \ set\ map\ \[namespace\ ensemble\ configure\ \$_\ -map\]\n\ \ \ \ \ \ \ \ foreach\ action\ \{faster\ slower\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ map\ \$action\ \[list\ ::apply\ \[list\ \{_\ action\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \$action\ \$_\ \{*\}\$args\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \$_\]\ \$_\ \$action\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ namespace\ ensemble\ configure\ \$_\ -map\ \$map\n\ \ \ \ \ \ \ \ namespace\ eval\ \$_\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ variable\ factor\ 1.0\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$_\n\ \ \ \ \}\n\n\}\nnamespace\ eval\ vartimer\ \{\n\ \ \ \ proc\ faster\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ factor\ factor\n\ \ \ \ \ \ \ \ set\ factor\ \[expr\ \{\$factor\ *\ 1.25\}\]\n\ \ \ \ \}\n\ \ \ \ proc\ slower\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ factor\ factor\n\ \ \ \ \ \ \ \ set\ factor\ \[expr\ \{\$factor\ *\ .25\}\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ lap\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ factor\ factor\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ elapsed\ upelapsed\n\ \ \ \ \ \ \ \ set\ lap\ \[\[namespace\ which\ timer\]::lap\ \$_\]\n\ \ \ \ \ \ \ \ set\ upelapsed\ \[expr\ \{\$upelapsed\ +\ (\$lap\ *\ \$factor)\}\]\n\ \ \ \ \}\n\}\n\n\nif\ 0\ \{\n======\n\nNow\ to\ try\ it\ out:\n\n======\n\}\nvartimer\ timer2\ntimer2\ faster\ntimer2\ faster\ntimer2\ start\nafter\ 2000\nputs\ \[timer2\ elapsed\]\n\nif\ 0\ \{\n======\n\nNow\ comes\ the\ fun\ part:\ \ Taking\ the\ functionality\ sketched\ out\ above\ and\npackaging\ it\ into\ a\ general\ system\ that's\ convenient\ to\ use.\ \ This\ increased\nthe\ complexity\ of\ the\ implementation,\ of\ course,\ but\ will\ make\ it\ easier\ to\ncompose\ and\ manage\ objects.\ \ To\ make\ something\ that's\ friendly\ to\ use,\ as\ well\nas\ more\ orthogonal,\ a\ few\ things\ will\ have\ to\ change.\ \ First,\ the\ basic\nfunctionality\ is\ encapsulated\ into\ a\ primordial\ object,\ the\ thing\ from\ which\nall\ other\ objects\ spring.\ \ This\ object\ will\ be\ a\ `\[namespace\ ensemble\]`,\ so\ it\nwill\ no\ longer\ be\ possible\ to\ call\ it\ directly\ to\ create\ new\ objects.\ \ Instead,\nit\ will\ have\ an\ object\ command,\ `new`,\ for\ that\ purpose.\ \ The\ two\ most\ basic\nthings\ an\ object\ should\ be\ able\ to\ do\ is\ configure\ what\ it\ is,\ and\ what\ it\ndoes.\ \ Thus,\ the\ next\ two\ commands\ to\ be\ implemented\ are\ `is`\ and\ `does`.\n\nBootstrapping\ the\ first\ object\ in\ the\ known\ universe\ is\ always\ a\ little\nproblematic,\ but\ in\ this\ case,\ it's\ not\ too\ bad,\ just\ a\ matter\ of\ calling\ a\ncouple\ of\ commands\ directly\ instead\ of\ calling\ them\ through\ the\ object\ name,\ as\nall\ other\ objects\ will\ do.\n\n======\n\}\n\nnamespace\ eval\ object\ \{\n\n\ \ \ \ proc\ is\ \{_\ what\}\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[string\ match\ ::*\ \$what\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ what\ \[uplevel\ 1\ \[list\ namespace\ which\ \$what\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ _path\ \[namespace\ eval\ \$_\ \{namespace\ path\}\]\n\ \ \ \ \ \ \ \ if\ \{\$what\ ni\ \$_path\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ eval\ \$_\ \[list\ namespace\ path\ \[list\ \$what\ \{*\}\$_path\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ map_orig\ \[namespace\ ensemble\ configure\ \$_\ -map\]\n\ \ \ \ \ \ \ \ set\ map_add\ \[namespace\ ensemble\ configure\ \$what\ -map\]\n\ \ \ \ \ \ \ \ namespace\ ensemble\ configure\ \$_\ -map\ \[dict\ merge\ \$map_add\ \$map_orig\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ does\ \{_\ args\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ map\ \[namespace\ ensemble\ configure\ \$_\ -map\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ what\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$what\]\ ==\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ what\ what\ target\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ target\ \$what\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ map\ \$what\ \[list\ ::apply\ \[list\ \{_\ target\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \$target\ \$_\ \{*\}\$args\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \$_\]\ \$_\ \$target\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ ensemble\ configure\ \$_\ -map\ \$map\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ keys\ \[namespace\ ensemble\ configure\ \$_\ -map\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ init\ \{_\ args\}\ \{\}\n\n\ \ \ \ proc\ new\ \{_\ name\}\ \{\n\ \ \ \ \ \ \ \ set\ name\ \[uplevel\ 1\ \[::list\ namespace\ eval\ \$name\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ ::namespace\ ensemble\ create\n\ \ \ \ \ \ \ \ \ \ \ \ ::namespace\ current\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \ \ \ \ set\ map\ \{\}\n\ \ \ \ \ \ \ \ foreach\ \{cmd\ target\}\ \[namespace\ ensemble\ configure\ \$_\ -map\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ args\ \[lassign\ \$target\ apply\ function\ arg1\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ function\ \[lreplace\ \$function\ 2\ 2\ \$name\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ target\ \[list\ \$apply\ \$function\ \$name\ \{*\}\$args\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ map\ \$cmd\ \$target\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ namespace\ ensemble\ configure\ \$name\ -map\ \$map\n\ \ \ \ \ \ \ \ namespace\ eval\ \$name\ \[list\ namespace\ path\ \[namespace\ eval\ \$_\ \{namespace\ path\}\]\]\n\ \ \ \ \ \ \ \ \$name\ is\ \$_\n\ \ \ \ \ \ \ \ \$name\ does\ init\n\ \ \ \ \ \ \ \ \$name\ init\n\ \ \ \ \ \ \ \ return\ \$name\n\ \ \ \ \}\n\n\ \ \ \ #\ bootstrap\ the\ system\n\ \ \ \ namespace\ ensemble\ create\n\ \ \ \ does\ \[namespace\ current\]\ is\n\ \ \ \ does\ \[namespace\ current\]\ does\n\ \ \ \ \[namespace\ current\]\ is\ \[namespace\ current\]\n\ \ \ \ \[namespace\ current\]\ does\ new\n\}\n\nif\ 0\ \{\n======\n\nLet's\ make\ an\ command\ to\ make\ it\ more\ convenient\ to\ evaluate\ scripts\ in\ the\nobject\ namespace:\n\n======\n\}\n\nnamespace\ eval\ object\ \{\n\ \ \ \ proc\ eval\ \{_\ args\}\ \{\n\ \ \ \ \ \ \ \ ::tailcall\ namespace\ eval\ \$_\ \[join\ \$args\]\n\ \ \ \ \}\n\}\nobject\ does\ eval\n\nif\ 0\ \{\n======\n\nMany\ object\ systems\ provide\ some\ way\ for\ an\ object\ command\ to\ call\ an\ object\ncommand\ by\ the\ same\ name\ in\ an\ ancestor\ object.\ \ Let's\ add\ one\ to\ the\ object.\nThe\ `\\0`\ namespace\ is\ just\ used\ as\ an\ empty\ namespace\ separate\ from\ the\ normal\nobject,\ that\ can\ be\ configured\ with\ the\ path\ of\ the\ object\ in\ order\ to\ look\ up\nthe\ next\ command.\ \ Since\ the\ path\ of\ an\ object\ may\ change\ dynamically,\ it's\nbest\ to\ grab\ that\ path\ and\ configure\ `\\0'\ with\ it\ just\ before\ the\ lookup.\n\n======\n\}\nnamespace\ eval\ object\ \{\n\ \ \ \ proc\ upcall\ \{_\ args\}\ \{\n\ \ \ \ \ \ \ \ set\ current\ \[uplevel\ 1\ \{namespace\ current\}\]\ \n\ \ \ \ \ \ \ \ set\ path\ \[namespace\ eval\ \$_\ \{namespace\ path\}\]\n\ \ \ \ \ \ \ \ while\ \{\[set\ idx\ \[lsearch\ -exact\ \$path\ \$current\]\]\ >=\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[lreplace\ \$path\ \$idx\ \$idx\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ namespace\ eval\ \\0\ \[list\ namespace\ path\ \$path\]\n\ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \{_\ cmd\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \$cmd\ \$_\ \{*\}\$args\n\ \ \ \ \ \ \ \ \}\ \[namespace\ current\]::\\0\]\ \$_\ \{*\}\$args\n\ \ \ \ \}\n\}\nobject\ does\ upcall\n\n\nif\ 0\ \{\n======\nNow\ that\ the\ primordial\ object\ exists,\ it\ can\ be\ used\ to\ create\ another\ object\nas\ the\ timer:\n======\n\}\n\n#rename\ timer\ \{\}\nobject\ new\ timer\ntimer\ does\ lap\ elapsed\ running\ start\ stop\n\nif\ 0\ \{\n======\n\nCreate\ a\ command\ to\ initialize\ the\ timer:\n\n======\n\}\n\n\ntimer\ eval\ \{\n\ \ \ \ proc\ init\ _\ \ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ elapsed\ elapsed\ running\ running\ start\ start\n\ \ \ \ \ \ \ \ set\ elapsed\ \[expr\ 0\]\n\ \ \ \ \ \ \ \ set\ running\ \[expr\ 0\]\n\ \ \ \ \ \ \ \ set\ start\ \[expr\ -1\]\n\ \ \ \ \ \ \ \ return\ \$_\n\ \ \ \ \}\n\}\n\n\ntimer\ new\ timer1\ntimer1\ start\nafter\ 2000\nputs\ \[timer1\ elapsed\]\n\nif\ 0\ \{\n======\n\nTo\ create\ a\ specialized\ timer,\ create\ a\ timer\ and\ then\ override\ the\ object\ncommands\ to\ as\ needed:\n\n======\n\}\n\ntimer\ new\ vartimer\nvartimer\ does\ faster\ slower\n\nvartimer\ eval\ \{\n\ \ \ \ proc\ init\ _\ \{\n\ \ \ \ \ \ \ \ namespace\ upvar\ \$_\ factor\ factor\n\ \ \ \ \ \ \ \ \$_\ upcall\ init\n\ \ \ \ \ \ \ \ set\ factor\ 1.0\n\ \ \ \ \}\n\}\n\nvartimer\ new\ timer2\ntimer2\ faster\ntimer2\ faster\ntimer2\ start\nafter\ 2000\nputs\ \[timer2\ elapsed\]\n\nif\ 0\ \{\n======\n\nThat's\ it.\ \ The\ object\ system\ presented\ on\ this\ page\ has\ a\ sufficient\ feature\nset\ to\ use\ in\ real\ projects.\ \ \[ycl\ shelf\]\ is\ built\ on\ many\ of\ these\ techniques,\nand\ \ features\ more\ bells\ and\ whistles.\n\n======\n\n<<categories>>\ object\ orientation\n\}} CALL {my revision {The Anatomy of an Object System}} CALL {::oo::Obj297060 process revision/The+Anatomy+of+an+Object+System} CALL {::oo::Obj297058 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