CINXE.COM
TclOO
<!DOCTYPE html> <html lang='en'> <head> <meta charset='utf-8'> <meta name='viewport' content='width=device-width, initial-scale=1'> <meta name='description' content='Tclers wiki'> <meta name='author' content=''> <link rel='icon' href='/img/favicon.ico'> <title>TclOO</title> <!-- Latest compiled and minified CSS --> <link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css'> <link rel='stylesheet' href='/css/nikit.css' type='text/css'> <link rel='stylesheet' href='/css/sh_style.css' type='text/css'> <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.0/css/theme.bootstrap_3.min.css' type='text/css'> <script src='//cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js'></script> </head> <body onload='sh_highlightDocument(); nikitUser();'> <nav class='navbar navbar-fixed-top navbar-inverse'> <div class='container'> <div class='navbar-header'> <button type='button' class='navbar-toggle' data-toggle='collapse' data-target='#myNavbar'> <span class='icon-bar'></span> <span class='icon-bar'></span> <span class='icon-bar'></span> </button> <ul class='nav navbar-nav'> <li class='dropdown'> <a class='dropdown-toggle' data-toggle='dropdown' href='#'> Tcler's Wiki<span class='caret'></span></a> <ul class='dropdown-menu scrollable-menu' role='menu'><li><a href='/welcome'>Home</a></li> <li><a rel='nofollow' href='/recent'>Changes</a></li> <li><a rel='nofollow' href='/_random'>Random page</a></li> <li><a rel='nofollow' href='/_new'>New page</a></li> </ul> </li> </ul> </div> <div class='collapse navbar-collapse' id='myNavbar'> <ul class='nav navbar-nav'> <li class='dropdown' id='li_idPageEdit' style='display:none'> <a class='dropdown-toggle' data-toggle='dropdown' href='#'><span id=name_idPageEdit>Page</span><span class='caret'></span></a> <ul class='dropdown-menu scrollable-menu' role='menu'><li><a rel='nofollow' href='/_edit/TclOO?A=1'>Comment</a></li> <li><a rel='nofollow' hidden='true' href='/_edit/TclOO'>Edit</a></li> <li><a rel='nofollow' href='/_upload/TclOO'>Upload</a></li> <li><a rel='nofollow' href='/ref/TclOO'>References</a></li> <li><a rel='nofollow' href='/history/TclOO'>History</a></li> <li><hr></li> <li><a href='#d7321abfaef52e711e1db8430ecc39629740c5f1e6b44991297291fa2422042d'> Examples </a> </li> <li><a href='#8a7583448005a20dbc9ffa2cf18c9f1625193a3d96398eafd18610156d98f8ba'> See Also </a> </li> <li><a href='#1748133d412ed701138d745cf455c4eac962a70a46168b1162b556a9b437094b'> C Interface </a> </li> <li><a href='#2d2d165c91430620524c2dc588a6cb6bf91287be43b9449da50124006094bace'> Development </a> </li> <li><a href='#6cf2844f8453ebe8213852a5e6978efa7c7586c8ad1e1e7f153ce83ec121b1c7'> Commands </a> </li> <li><a href='#317dcc072f9a2320852faa5e2fbe937aac9cfc70cea1abca939d54861a22fe7d'> Filters </a> </li> <li><a href='#13ef36d3d56264c8e619450110b712fc8c2992f04a1a4d3bba8abea785ac3e97'> <b>Method</b> Commands </a> </li> <li><a href='#47742718299e82699bc374b81e6ab6b22c2b19c674703379e03143e714e9e3c1'> Description </a> </li> <li><a href='#e4d548b0c196724e76f8154ae37358e909bb74b017366d1e930dcf48af64048e'> News </a> </li> <li><a href='#c7bee56a007e5e3a7a3e333eeda62fc741722754b133672bebb41dc18c2be9a6'> Basic Example </a> </li> <li><a href='#660fb79034e4442765d1ae0c93770f4669f77cf29221787d6ad743f71d7af992'> TclOO::ext </a> </li> <li><a href='#f0d0837119d2e68a0faac82afcb4df3df16c9b91e1f5f13351601d6cf748612c'> Discussion </a> </li> <li><a href='#0c56197ff466e986d2cc16f60c5356a91a78ba2a7fb6e1444b860abacc1d6209'> Aspects with TclOO </a> </li> <li><a href='#1f0d5c8b0b823ff181504b894da779569435b133954e86cf6d4b9e15d2d8488f'>Performance Measurement</a> </li> <li><a href='#256420a9344bbb0305616444b488a9767c9dcfdef8f4645cc3f78fc9b575c18f'> Performance Analysis Script </a> </li> </ul> </li> <li class='dropdown' id='li_idPageNoEdit' style='display:none'> <a class='dropdown-toggle' data-toggle='dropdown' href='#'><span id=name_idPageNoEdit>Page</span><span class='caret'></span></a> <ul class='dropdown-menu scrollable-menu' role='menu'><li><a rel='nofollow' href='/ref/TclOO'>References</a></li> <li><a rel='nofollow' href='/history/TclOO'>History</a></li> <li><hr></li> <li><a href='#d7321abfaef52e711e1db8430ecc39629740c5f1e6b44991297291fa2422042d'> Examples </a> </li> <li><a href='#8a7583448005a20dbc9ffa2cf18c9f1625193a3d96398eafd18610156d98f8ba'> See Also </a> </li> <li><a href='#1748133d412ed701138d745cf455c4eac962a70a46168b1162b556a9b437094b'> C Interface </a> </li> <li><a href='#2d2d165c91430620524c2dc588a6cb6bf91287be43b9449da50124006094bace'> Development </a> </li> <li><a href='#6cf2844f8453ebe8213852a5e6978efa7c7586c8ad1e1e7f153ce83ec121b1c7'> Commands </a> </li> <li><a href='#317dcc072f9a2320852faa5e2fbe937aac9cfc70cea1abca939d54861a22fe7d'> Filters </a> </li> <li><a href='#13ef36d3d56264c8e619450110b712fc8c2992f04a1a4d3bba8abea785ac3e97'> <b>Method</b> Commands </a> </li> <li><a href='#47742718299e82699bc374b81e6ab6b22c2b19c674703379e03143e714e9e3c1'> Description </a> </li> <li><a href='#e4d548b0c196724e76f8154ae37358e909bb74b017366d1e930dcf48af64048e'> News </a> </li> <li><a href='#c7bee56a007e5e3a7a3e333eeda62fc741722754b133672bebb41dc18c2be9a6'> Basic Example </a> </li> <li><a href='#660fb79034e4442765d1ae0c93770f4669f77cf29221787d6ad743f71d7af992'> TclOO::ext </a> </li> <li><a href='#f0d0837119d2e68a0faac82afcb4df3df16c9b91e1f5f13351601d6cf748612c'> Discussion </a> </li> <li><a href='#0c56197ff466e986d2cc16f60c5356a91a78ba2a7fb6e1444b860abacc1d6209'> Aspects with TclOO </a> </li> <li><a href='#1f0d5c8b0b823ff181504b894da779569435b133954e86cf6d4b9e15d2d8488f'>Performance Measurement</a> </li> <li><a href='#256420a9344bbb0305616444b488a9767c9dcfdef8f4645cc3f78fc9b575c18f'> Performance Analysis Script </a> </li> </ul> </li> <li><a href="/page/Showcase">Showcase</a></li> <li><a href="/page/Tcl+Tutorial+Lesson+0">Tutorial</a></li> <li><a href="/page/Articles">Articles</a></li> <li><a href="/page/Tcl+Playground">Playground</a></li> <li class='dropdown'> <a class='dropdown-toggle' data-toggle='dropdown' href='#'> Help<span class='caret'></span></a> <ul class='dropdown-menu scrollable-menu' role='menu'><li><a rel='nofollow' href='/page/Help'>Page Markup</a></li> <li><a rel='nofollow' href='/page/How+do+Wiki+Categories+work'>Wiki Categories</a></li> <li><a rel='nofollow' href='/page/Contents'>Topics</a></li> <li><a rel='nofollow' target='_blank' href='https://chiselapp.com/user/stevel/repository/nikit/ticket'>Report Problems</a></li> <li><a rel='nofollow' href='/privacy'>Privacy</a></li> <li><a rel='nofollow' href='/license'>License</a></li> </ul> </li> </ul> <ul class='nav navbar-nav navbar-right'> <li class='dropdown'> <a class='dropdown-toggle' data-toggle='dropdown' href='#'><span id=name_SMenu>User</span><span class='caret'></span></a> <ul class='dropdown-menu' id='ul_SMenu'> </ul> </li> </ul> <form class='navbar-form navbar-right' method='post' action='/search' id='searchform'> <input name='Q' type='text' class='form-control' placeholder='Search...'/> <input type="hidden" name="sites" value="wiki.tcl-lang.org"/> </form> </div> </div> </nav> <div class='container'> <div class='row'> <div class='col-xs-12'> <h2>TclOO</h2> </div> </div> <div class='row'> <div class='col-xs-12'> <p class='mkup_p'><b class='mkup_b'><a rel='nofollow' class='mkup_a' href='https://www.tcl-lang.org/man/tcl/TclCmd/object.htm'>TclOO <span class='glyphicon glyphicon-globe' aria-hidden='true'></span></a></b>, by <a class='mkup_a mkup_known' href='/page/DKF'>Donal Fellows</a>, is both a toolkit for creating <a class='mkup_a mkup_known' href='/page/Object+orientation'>object systems</a>, and an object system in its own right. As of Tcl <a class='mkup_a mkup_known' href='/page/Changes+in+Tcl%2FTk+8%2E6'>8.6</a>, is part of the <a class='mkup_a mkup_known' href='/page/The+Tcl+Core'>core</a> distribution. </p><dl class='mkup_dl'><dt class='mkup_dt'><i class='mkup_i'>It just works. Kudos to <a class='mkup_a mkup_known' href='/page/Donal+Fellows'>Donal</a></i></dt><dd class='mkup_dd'>- <a class='mkup_a mkup_known' href='/page/Will+Duquette'>Will Duquette</a>,<a class='mkup_a mkup_known' href='/page/Twentieth+Annual+Tcl%2FTk+Conference+%282013%29'>Twentieth Annual Tcl/Tk Conference (2013)</a></dd></dl> <h2 id='d7321abfaef52e711e1db8430ecc39629740c5f1e6b44991297291fa2422042d' class='mkup_h1'> Examples </h2><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/Playing+with+TclOO'>Playing with TclOO</a></dt><dd class='mkup_dd'></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/TclOO+Tricks'>TclOO Tricks</a></dt><dd class='mkup_dd'></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/TclOO+Channels'>TclOO Channels</a></dt><dd class='mkup_dd'></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/coroutine'>coroutine</a></dt><dd class='mkup_dd'>contains a TclOO example by <a class='mkup_a mkup_known' href='/page/CMcC'>CMcC</a></dd></dl> <h2 id='8a7583448005a20dbc9ffa2cf18c9f1625193a3d96398eafd18610156d98f8ba' class='mkup_h1'> See Also </h2><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/TIP+%23257%3A+Object+Orientation+for+Tcl'>TIP #257: Object Orientation for Tcl</a></dt><dd class='mkup_dd'></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/Megawidgets+with+TclOO'>Megawidgets with TclOO</a></dt><dd class='mkup_dd'></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/TclOO+and+configure'>TclOO and configure</a></dt><dd class='mkup_dd'>Work in progress for a configuration system to go with above megawidgets stuff</dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/Abstract+base+classes+with+TclOO'>Abstract base classes with TclOO</a></dt><dd class='mkup_dd'></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/Fun+with+TclOO%2C+coroutines+and+apply'>Fun with TclOO, coroutines and apply</a></dt><dd class='mkup_dd'></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/TclOO+Method+Dispatch'>TclOO Method Dispatch</a></dt><dd class='mkup_dd'></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/Serializing+TclOO+objects'>Serializing TclOO objects</a></dt><dd class='mkup_dd'></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/typedlist'>typedlist</a></dt><dd class='mkup_dd'></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/TclOO+trace+filter'>TclOO trace filter</a></dt><dd class='mkup_dd'></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/MeTOO'>MeTOO</a></dt><dd class='mkup_dd'>emulates TclOO for Tcl 8.4</dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/Prototype+Pattern+in+Tcl'>Prototype Pattern in Tcl</a></dt><dd class='mkup_dd'>Includes a small TclOO example by <a class='mkup_a mkup_known' href='/page/DKF'>dkf</a>.</dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/TclOO+Tutorial'>TclOO Tutorial</a></dt><dd class='mkup_dd'></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/JBR%27s+tcloo%2Etcl'>JBR's tcloo.tcl</a></dt><dd class='mkup_dd'></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/Self+on+a+class%2Dbased+OO+system'>Self on a class-based OO system</a></dt><dd class='mkup_dd'>Illustrates the trick of mixing a class into itself so that it can serve as a prototype in a prototype-oriented objected system. The TclOO variant of <a class='mkup_a mkup_known' href='/page/ycl+shelf'>ycl shelf</a> will also use this mechanism.</dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/TclOO+widget%2Fobject+framework'>TclOO widget/object framework</a>, by <a class='mkup_a mkup_known' href='/page/RZ'>RZ</a></dt><dd class='mkup_dd'>adds some features to vanilla TclOO, including private variables, some enhancements to <span class='mkup_tt'>constructor</span> and <span class='mkup_tt'>destructor</span>, new class methods like <span class='mkup_tt'>option ...</span> and <span class='mkup_tt'>component ...</span></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a rel='nofollow' class='mkup_a' href='http://www.magicsplat.com/articles/oo.html'>TclOO Introductory Article <span class='glyphicon glyphicon-globe' aria-hidden='true'></span></a></dt><dd class='mkup_dd'>Please redirect any comments or corrections to the <a class='mkup_a mkup_known' href='/page/BOOK+Tcl+Programming+for+Windows'>BOOK Tcl Programming for Windows</a> page.</dd></dl> <h2 id='1748133d412ed701138d745cf455c4eac962a70a46168b1162b556a9b437094b' class='mkup_h1'> C Interface </h2><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/How+to+embed+Tcl+in+C+applications'>How to embed Tcl in C applications</a></dt><dd class='mkup_dd'>Includes TclOO examples.</dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/Writing+a+TclOO+Method+in+C'>Writing a TclOO Method in C</a></dt><dd class='mkup_dd'></dd></dl> <h2 id='2d2d165c91430620524c2dc588a6cb6bf91287be43b9449da50124006094bace' class='mkup_h1'> Development </h2><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/TclOO+WishList+and+Work+Roster'>TclOO WishList and Work Roster</a></dt><dd class='mkup_dd'></dd></dl> <h2 id='6cf2844f8453ebe8213852a5e6978efa7c7586c8ad1e1e7f153ce83ec121b1c7' class='mkup_h1'> Commands </h2><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/oo%3A%3Aclass'>::oo::class</a></dt><dd class='mkup_dd'>new in 8.6</dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/oo%3A%3Acopy'>::oo::copy</a></dt><dd class='mkup_dd'>new in 8.6 </dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/oo%3A%3Adefine'>::oo::define</a></dt><dd class='mkup_dd'>new in 8.6 </dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/oo%3A%3Aobjdefine'>::oo::objdefine</a></dt><dd class='mkup_dd'></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/oo%3A%3Aobject'>::oo::object</a></dt><dd class='mkup_dd'></dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/info'>info</a></dt><dd class='mkup_dd'> </dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/info+class'>info class</a></dt><dd class='mkup_dd'>provides introspection of classes (many subcommands)</dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/info+object'>info object</a></dt><dd class='mkup_dd'>provides introspection of objects (many subcommands)</dd></dl> <h2 id='317dcc072f9a2320852faa5e2fbe937aac9cfc70cea1abca939d54861a22fe7d' class='mkup_h1'> Filters </h2><dl class='mkup_dl'><dt class='mkup_dt'><a rel='nofollow' class='mkup_a' href='https://wiki.tcl-lang.org/page/Profiling+a+TclOO+class'>Profiling a TclOO class <span class='glyphicon glyphicon-globe' aria-hidden='true'></span></a></dt><dd class='mkup_dd'>Uses a filter mix-in to time method calls.</dd></dl> <h2 id='13ef36d3d56264c8e619450110b712fc8c2992f04a1a4d3bba8abea785ac3e97' class='mkup_h1'> <a class='mkup_a mkup_known' href='/page/method'>Method</a> Commands </h2><p class='mkup_p'>The following commands are only available within the body of a method</p><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/my'>my</a></dt><dd class='mkup_dd'>new in 8.6</dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/next'>next</a></dt><dd class='mkup_dd'>new in 8.6</dd></dl><dl class='mkup_dl'><dt class='mkup_dt'><a class='mkup_a mkup_known' href='/page/self+%2D+TclOO'>self</a></dt><dd class='mkup_dd'>new in 8.6</dd></dl> <h2 id='47742718299e82699bc374b81e6ab6b22c2b19c674703379e03143e714e9e3c1' class='mkup_h1'> Description </h2><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/DKF'>DKF</a> (mostly): </p><p class='mkup_p'><b class='mkup_b'>TclOO</b> is a core for other OO extensions, but in order to do that job properly it also needs to be a basic OO framework itself. The other thing that it isn't is a class library. That can go in <a class='mkup_a mkup_known' href='/page/Tcllib'>tcllib</a> just nicely.</p><p class='mkup_p'>OO support in the core distribution can be completely ignored except when it is providing a specific benefit to a script. At an implementation level, the benefit is that it scopes the development and keeps the amount of work required sane and the delivery schedule practical. You might or might not think of this as a benefit... :-)</p><p class='mkup_p'>TclOO borrows many concepts from <a class='mkup_a mkup_known' href='/page/XOTcl'>XOTcl</a>, so there's definite continuity from Smalltalk in there. Not everything though; <a class='mkup_a mkup_known' href='/page/incr+Tcl'>incr Tcl</a> was an influence too and that's got <a class='mkup_a mkup_known' href='/page/C%2B%2B'>C++</a> genes.</p><p class='mkup_p'>Developers may choose to use <span class='mkup_tt'>::tcl::oo</span> directly to do their work, or they may choose to use other <a class='mkup_a mkup_known' href='/page/Object+orientation'>object systems</a>, e.g., <a class='mkup_a mkup_known' href='/page/Snit'>snit</a>, <a class='mkup_a mkup_known' href='/page/incr+Tcl'>incr tcl</a>, <a class='mkup_a mkup_known' href='/page/XOTcl'>XOTcl</a>, which themselves use TclOO and then provide additional functionality/flavour. </p><p class='mkup_p'>In terms of rewriting things to use TclOO, some classes probably will be rewritten, e.g. quite possibly code to support <span class='mkup_tt'><a class='mkup_a mkup_known' href='/page/chan+create'>chan create</a></span> better, maybe a <a class='mkup_a mkup_known' href='/page/megawidget'>megawidget</a> framework, and <a class='mkup_a mkup_known' href='/page/TDBC'>TDBC</a> of course) but there won't be a vast number. The whole world needn't be changed. Tcl was working fairly well beforehand.</p> <h2 id='e4d548b0c196724e76f8154ae37358e909bb74b017366d1e930dcf48af64048e' class='mkup_h1'> News </h2><p class='mkup_p'>TclOO 1.0.1 was released on 2013-09-26. It corresponds to the version included as part of Tcl 8.6.1. <a rel='nofollow' class='mkup_a' href='http://sourceforge.net/projects/tcl/files/TclOO%20Package/1.0.1/%|%Download%|%'>http://sourceforge.net/projects/tcl/files/TclOO%20Package/1.0.1/%|%Download%|% <span class='glyphicon glyphicon-globe' aria-hidden='true'></span></a>.</p><p class='mkup_p'>TclOO 1.0 was released on 2012-12-21. It corresponds to the version included as part of Tcl 8.6.0. <a rel='nofollow' class='mkup_a' href='http://sourceforge.net/projects/tcl/files/TclOO%20Package/1.0/%|%Download%|%'>http://sourceforge.net/projects/tcl/files/TclOO%20Package/1.0/%|%Download%|% <span class='glyphicon glyphicon-globe' aria-hidden='true'></span></a>.</p><p class='mkup_p'>TclOO 0.6 has been released on 2008-10-14. It corresponds to the version included as part of Tcl 8.6a3.</p><p class='mkup_p'><i class='mkup_i'>Original announcement on <a rel='nofollow' class='mkup_a' href='news:comp.lang.tcl'>news:comp.lang.tcl <span class='glyphicon glyphicon-globe' aria-hidden='true'></span></a> on 01-Oct-2007</i> (note links are outdated now):</p><div class='sh_sourceCode'><button class='copybtn btn pull-right' data-clipboard-target='#mkup_code_0' title='Click to copy code snippet to clipboard'><span class='glyphicon glyphicon-copy' aria-hidden='true'></span></button><pre id='mkup_code_0' class='mkup_pre sh_sourceCode'>I'm very pleased to announce that TclOO version 0.1 is now released. It's hosted in the Tcl project at [SourceForge], so you can download the source package from: http://sf.net/project/showfiles.php?group_id=10894&package_id=247402 It requires Tcl 8.5b1 to build and operate; see the enclosed `README.txt` for details on how to build this TEA-based package. No promises on whether I'll do a binary package for any platforms as yet. :-) Details about this package can be found in the Wiki, naturally, at https://wiki.tcl-lang.org/TclOO and any problems should be reported using Tcl's issue trackers at http://sf.net/tracker/?group_id=10894&atid=110894 with the summary field prefixed by "TclOO:".</pre></div> <h2 id='c7bee56a007e5e3a7a3e333eeda62fc741722754b133672bebb41dc18c2be9a6' class='mkup_h1'> Basic Example </h2> <div class='sh_sourceCode'><button class='copybtn btn pull-right' data-clipboard-target='#mkup_code_1' title='Click to copy code snippet to clipboard'><span class='glyphicon glyphicon-copy' aria-hidden='true'></span></button><pre id='mkup_code_1' class='sh_tcl sh_sourceCode'>package require TclOO; #if loading for the first time; not required on Tcl 8.6 oo::class create summation { constructor {} { variable v 0 } method add x { variable v incr v $x } method value {} { variable v return $v } destructor { variable v puts "Ended with value $v" } } set sum [summation new] puts "Start with [$sum value]" for {set i 1} {$i <= 10} {incr i} { puts "Add $i to get [$sum add $i]" } $sum destroy ;# only destroy the $sum object. 'summation destroy' destroys ALL summation objects --Duoas</pre></div><p class='mkup_p'>which gives:</p><div class='sh_sourceCode'><button class='copybtn btn pull-right' data-clipboard-target='#mkup_code_2' title='Click to copy code snippet to clipboard'><span class='glyphicon glyphicon-copy' aria-hidden='true'></span></button><pre id='mkup_code_2' class='sh_tcl sh_sourceCode'>Start with 0 Add 1 to get 1 Add 2 to get 3 Add 3 to get 6 Add 4 to get 10 Add 5 to get 15 Add 6 to get 21 Add 7 to get 28 Add 8 to get 36 Add 9 to get 45 Add 10 to get 55 Ended with value 55</pre></div><p></p><button class='mkup_button' type='button' id='togglediscussionbutton0' onclick='toggleDiscussion(0);'>Show discussion</button><div class='mkup_discussion' id='discussion0'><p class='mkup_p'>Should you see the error message</p><div class='sh_sourceCode'><button class='copybtn btn pull-right' data-clipboard-target='#mkup_code_3' title='Click to copy code snippet to clipboard'><span class='glyphicon glyphicon-copy' aria-hidden='true'></span></button><pre id='mkup_code_3' class='mkup_pre sh_sourceCode'>attempt to provide package TclOO 0.1.1 failed: package TclOO 0.1 provided instead</pre></div><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/Duoas'>Duoas</a> If I should see that message, then what?</p><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/DKF'>DKF</a>: Then stop using that old version! I really don't recommend using less than 1.0 nowadays…</p></div><p></p><button class='mkup_button' type='button' id='togglediscussionbutton1' onclick='toggleDiscussion(1);'>Show discussion</button><div class='mkup_discussion' id='discussion1'><h2 id='660fb79034e4442765d1ae0c93770f4669f77cf29221787d6ad743f71d7af992' class='mkup_h1'> TclOO::ext </h2><p class='mkup_p'>I collected some TclOO extension in a package here: <a rel='nofollow' class='mkup_a' href='https://github.com/arthurschreiber/tcloo-ext'>https://github.com/arthurschreiber/tcloo-ext <span class='glyphicon glyphicon-globe' aria-hidden='true'></span></a></p><p class='mkup_p'>Currently included is a Reference Counting system inspired by ObjectiveC/Cocoa to make memory management easier and a class method inheritance through MetaClasses (not using mixins).</p> <h2 id='f0d0837119d2e68a0faac82afcb4df3df16c9b91e1f5f13351601d6cf748612c' class='mkup_h1'> Discussion </h2></div><p></p><button class='mkup_button' type='button' id='togglediscussionbutton2' onclick='toggleDiscussion(2);'>Show discussion</button><div class='mkup_discussion' id='discussion2'><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/APN'>APN</a> I don't quite follow the discussion below about automatically bringing variables into scope. Isn't that what the <span class='mkup_tt'>variable</span> inside a class definition does?</p><div class='sh_sourceCode'><button class='copybtn btn pull-right' data-clipboard-target='#mkup_code_4' title='Click to copy code snippet to clipboard'><span class='glyphicon glyphicon-copy' aria-hidden='true'></span></button><pre id='mkup_code_4' class='sh_tcl sh_sourceCode'>class create C { variable a b }</pre></div><p class='mkup_p'>would have variables <span class='mkup_tt'>a</span> and <span class='mkup_tt'>b</span> automatically brought into scope in all methods. Perhaps the discussion originated before <span class='mkup_tt'>variable</span> was implemented. If someone can confirm this, please delete this and the discussion below because it is misleading.</p><dl class='mkup_dl'><dt class='mkup_dt'></dt><dd class='mkup_dd'><a class='mkup_a mkup_known' href='/page/DKF'>DKF</a>: Indeed, that's what the <span class='mkup_tt'>variable</span> declaration does. Now. <i class='mkup_i'>It didn't when the discussion was held.</i> It also doesn't bring in all variables because that turns out to be more problematic when mixed with inheritance.</dd></dl><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/JCW'>jcw</a> 2007-06-04:</p><p class='mkup_p'>Is there some nice idiom for the following?</p><div class='sh_sourceCode'><button class='copybtn btn pull-right' data-clipboard-target='#mkup_code_5' title='Click to copy code snippet to clipboard'><span class='glyphicon glyphicon-copy' aria-hidden='true'></span></button><pre id='mkup_code_5' class='sh_tcl sh_sourceCode'>my variable {*}[info vars [namespace current]::*]</pre></div><p class='mkup_p'>IOW, set up methods to automatically have access to all object state as plain variables (as in Itcl). The above line would be added in front of all method definitions, using a small wrapper (am generating methods dynamically anyway).</p><p class='mkup_p'>This assumes that all variables are defined in the constructor.</p><p class='mkup_p'><i class='mkup_i'><a class='mkup_a mkup_known' href='/page/escargo'>escargo</a></i> Does this use of variable contrast confusingly with the Tcl <a class='mkup_a mkup_known' href='/page/variable'>variable</a> where something like that would assign the names of half the variables as the values of the other half of the variables?</p><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/JCW'>jcw</a> - Well, I'm just trying it out, so don't shoot me ;) - although so far I tend prefer this over the "variable" cmd.</p><p class='mkup_p'><i class='mkup_i'><a class='mkup_a mkup_known' href='/page/escargo'>escargo</a></i> - I was just asking a question. It's just that having <b class='mkup_b'>my variable</b> work not like <a class='mkup_a mkup_known' href='/page/variable'>variable</a> might be considered confusing.</p><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/JCW'>jcw</a> - Here's an example with some output which may help those who don't have TclOO yet:</p><div class='sh_sourceCode'><button class='copybtn btn pull-right' data-clipboard-target='#mkup_code_6' title='Click to copy code snippet to clipboard'><span class='glyphicon glyphicon-copy' aria-hidden='true'></span></button><pre id='mkup_code_6' class='sh_tcl sh_sourceCode'>oo::class create dog { method a {} { puts a1-[namespace current] puts a2-[namespace path] foreach x [namespace path] { puts a3-$x-[info commands ${x}::*] } puts a4-[info vars [namespace current]::*] my variable e set e f puts a5-[info vars [namespace current]::*] } self method b {} { puts b1-[namespace current] puts b2-[namespace path] foreach x [namespace path] { puts b3-$x-[info commands ${x}::*] } puts b4-[info vars [namespace current]::*] my variable e set e f puts b5-[info vars [namespace current]::*] } } dog create fifi fifi a dog b # Output: # a1-::oo::Obj4 # a2-::oo::Helpers # a3-::oo::Helpers-::oo::Helpers::self ::oo::Helpers::next # a4- # a5-::oo::Obj4::e # b1-::oo::Obj3 # b2-::oo::Helpers ::oo # b3-::oo::Helpers-::oo::Helpers::self ::oo::Helpers::next # b3-::oo-::oo::InfoClass ::oo::class ::oo::InfoObject ::oo::object \ # ::oo::copy ::oo::define # b4- # b5-::oo::Obj3::e</pre></div><dl class='mkup_dl'><dt class='mkup_dt'></dt><dd class='mkup_dd'><a class='mkup_a mkup_known' href='/page/MHo'>MHo</a> 2015-02-24 This doesn't work for me. There's no command 'dog b'. Should it be '<span class='mkup_tt'>self method b…</span>' instead of '<span class='mkup_tt'>self.method b…</span>' ? Would be fine if there where a 'TclOO for OO-Dummies' somewhere....</dd><dt class='mkup_dt'></dt><dd class='mkup_dd'><a class='mkup_a mkup_known' href='/page/DKF'>DKF</a>: Yes, it should. The <span class='mkup_tt'>self.<i class='mkup_i'>blah</i></span> syntax was an interim thing that got removed once I had the more general <span class='mkup_tt'>self</span> syntax.</dd></dl> <p class='mkup_p'>As you can see, each class and each instance gets its own namespace. Note also that class Dog ended up as namespace Obj3, even though it was constructed with a specific name (which is not necessarily globally unique, though).</p><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/DKF'>DKF</a>: I've been experimenting for a while now with OO systems, and a <b class='mkup_b'>my variable</b> that brings every variable in the object into scope is probably not what you want as it causes great problems in subclasses (i.e. clashes between subclasses' variables and local variables). Instead, I think that being able to pick up all the variables defined within a particular class would be far more useful. OTOH, it's not at all trivial to implement (I think I expose enough API that it can be done through the use of class metadata, but I'm not certain) so I'm not in a hurry to change things.</p><p class='mkup_p'>It was a deliberate decision to make <b class='mkup_b'>my variable</b> different from <span class='mkup_tt'><a class='mkup_a mkup_known' href='/page/variable'>variable</a></span>. The latter has syntax that is almost never what anyone wants, and so is <i class='mkup_i'>a priori</i> suboptimal. Hence I went for something that was more likely to be what you need. :-)</p><p class='mkup_p'><i class='mkup_i'><a class='mkup_a mkup_known' href='/page/escargo'>escargo</a>: Well, I wondered if you did it on purpose, and you did. And I see it was for what you think is a good reason.</i></p><p class='mkup_p'>Also, as noted, the internal namespaces have names that are not necessarily those of the created object, and their names are deliberately not documented (i.e. they could change between point releases with no warning). Use the introspection facilities to go from one to the other.</p><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/APW'>APW</a> 2007-06-05: </p><p class='mkup_p'>@ <a class='mkup_a mkup_known' href='/page/JCW'>jcw</a>: I am working on an extended version of <a class='mkup_a mkup_known' href='/page/DKF'>dkf</a>'s code suitable for Itcl, which would have solutions for some of the problems you have mentioned above. For example I am using <span class='mkup_tt'><a class='mkup_a mkup_known' href='/page/apply'>apply</a></span> and <span class='mkup_tt'><a class='mkup_a mkup_known' href='/page/namespace+upvar'>namespace upvar</a></span> and <span class='mkup_tt'><a class='mkup_a mkup_known' href='/page/namespace+unknown'>namespace unknown</a></span> to generate Itcl methods, which have access to all the class variables in the class hierarchy (if they are not private) etc. Using only the name of a variable as in Itcl is possible, same for call of Itcl methods without the "my" in front. If you are interested please contact me directly, the implementation is not yet ready for real testing.</p><p class='mkup_p'>@<a class='mkup_a mkup_known' href='/page/DKF'>dkf</a>: If I know what I really need additionally for Itcl I will contact you and we can try to perhaps get a merged version. At the moment all my modifications are additional functionality so that the original functionality should work as before with also running all your tests without problems. </p></div><p></p><button class='mkup_button' type='button' id='togglediscussionbutton3' onclick='toggleDiscussion(3);'>Show discussion</button><div class='mkup_discussion' id='discussion3'> <h2 id='0c56197ff466e986d2cc16f60c5356a91a78ba2a7fb6e1444b860abacc1d6209' class='mkup_h1'> Aspects with TclOO </h2><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/DKF'>DKF</a>: The following example is ripped from the documentation of <a class='mkup_a mkup_known' href='/page/next'>next</a>:</p><div class='sh_sourceCode'><button class='copybtn btn pull-right' data-clipboard-target='#mkup_code_7' title='Click to copy code snippet to clipboard'><span class='glyphicon glyphicon-copy' aria-hidden='true'></span></button><pre id='mkup_code_7' class='sh_tcl sh_sourceCode'>oo::class create cache { filter Memoize method Memoize args { # Do not filter the core method implementations if {[lindex [self target] 0] eq "::oo::object"} { return [next {*}$args] } # Check if the value is already in the cache my variable ValueCache set key [self target],$args if {[info exist ValueCache($key)]} { return $ValueCache($key) } # Compute value, insert into cache, and return it return [set ValueCache($key) [next {*}$args]] } method flushCache {} { my variable ValueCache unset ValueCache # Skip the cacheing return -level 2 "" } } oo::object create demo oo::objdefine demo { mixin cache method compute {a b c} { after 3000 ;# Simulate deep thought return [expr {$a + $b * $c}] } method compute2 {a b c} { after 3000 ;# Simulate deep thought return [expr {$a * $b + $c}] } }</pre></div><div class='sh_sourceCode'><pre class='sh_tcl sh_sourceCode'>puts [demo compute 1 2 3] <i class='mkup_i'>? prints "7" after delay</i> puts [demo compute2 4 5 6] <i class='mkup_i'>? prints "26" after delay</i> puts [demo compute 1 2 3] <i class='mkup_i'>? prints "7" instantly</i> puts [demo compute2 4 5 6] <i class='mkup_i'>? prints "26" instantly</i> puts [demo compute 4 5 6] <i class='mkup_i'>? prints "34" after delay</i> puts [demo compute 4 5 6] <i class='mkup_i'>? prints "34" instantly</i> puts [demo compute 1 2 3] <i class='mkup_i'>? prints "7" instantly</i> demo flushCache puts [demo compute 1 2 3] <i class='mkup_i'>? prints "7" after delay</i></pre></div><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/JCW'>jcw</a>: ''Way cool, great separation of functionality. Next step: a Metakit backed cache? ;)</p><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/DKF'>DKF</a>: I've thought more about this, and have written an <a class='mkup_a mkup_known' href='/page/Aspect+Support+Class+for+TclOO'>Aspect Support Class for TclOO</a>.</p><hr class='mkup_hr'><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/APW'>APW</a> 2007-06-06: For discussion of Itcl related topics for a new implementation based on this TIP see <a class='mkup_a mkup_known' href='/page/tclOO+missing+features+for+Itcl'>tclOO missing features for Itcl</a></p> <h2 id='1f0d5c8b0b823ff181504b894da779569435b133954e86cf6d4b9e15d2d8488f' class='mkup_h1'>Performance Measurement</h2><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/DKF'>DKF</a> 2007-09-20: As seen in my Tck2k7 paper, TclOO is really quite fast. Here's those performance figures (correct with 8.5b1 on my ancient laptop).</p><table class='mkup_data'><tr class='mkup_tr'><th class='mkup_th'> OO System </th><th class='mkup_th'> Objects Made (s?¹) </th><th class='mkup_th'> Method Calls (s?¹) </th></tr><tr class='mkup_trodd'><td class='mkup_td'> TclOO 0.1 </td><td class='mkup_td'> 32800 </td><td class='mkup_td'> 206000 </td></tr><tr class='mkup_treven'><td class='mkup_td'> itcl 3.4.0 </td><td class='mkup_td'> 22500 </td><td class='mkup_td'> 128000 </td></tr><tr class='mkup_trodd'><td class='mkup_td'> XOTcl 1.5.5 </td><td class='mkup_td'> 18500 </td><td class='mkup_td'> 87500 </td></tr><tr class='mkup_treven'><td class='mkup_td'> Snit 2.1 </td><td class='mkup_td'> 2080 </td><td class='mkup_td'> 54700 </td></tr><tr class='mkup_trodd'><td class='mkup_td'> Snit 1.2 </td><td class='mkup_td'> 1020 </td><td class='mkup_td'> 24700 </td></tr><tr class='mkup_treven'><td class='mkup_td'> stooop 4.4.1 </td><td class='mkup_td'> 13900 </td><td class='mkup_td'> 26700 </td></tr></table><p class='mkup_p'><b class='mkup_b'>Notes:</b> It turns out that <a class='mkup_a mkup_known' href='/page/stooop'>stooop</a> non-virtual methods are much faster, but they're not comparable with the other methods as they do not allow overriding of the method by subclasses, so I used the (comparable) virtual methods instead, which are much slower.</p><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/DKF'>DKF</a>: Reanalysed with modern hardware and new versions of XOTcl, TclOO and snit (~3 sig. figures) - this machine doesn't seem to have stooop:</p><table class='mkup_data'><tr class='mkup_tr'><th class='mkup_th'> OO System </th><th class='mkup_th'> Objects Made (s?¹) </th><th class='mkup_th'> Method Calls (s?¹) </th></tr><tr class='mkup_trodd'><td class='mkup_td'> TclOO 0.3 </td><td class='mkup_td'> 121000 </td><td class='mkup_td'> 981000 </td></tr><tr class='mkup_treven'><td class='mkup_td'> itcl 3.4.0 </td><td class='mkup_td'> 87900 </td><td class='mkup_td'> 573000 </td></tr><tr class='mkup_trodd'><td class='mkup_td'> XOTcl 1.6.0 </td><td class='mkup_td'> 87200 </td><td class='mkup_td'> 404000 </td></tr><tr class='mkup_treven'><td class='mkup_td'> Snit 2.2.1 </td><td class='mkup_td'> 7190 </td><td class='mkup_td'> 881000 </td></tr></table><p class='mkup_p'>All are packages built by ActiveState, running on Tcl 8.5.2. (I see differences in my own tests, but can't tell what their origin is.)</p><p class='mkup_p'>Analyzing those figures, we see (from the itcl baseline) that the machine is about 4.25 times faster (average). We therefore can see that TclOO is getting a (little) better at method dispatch though it is slower at object construction. We also see that XOTcl has improved a lot on the construction front, though it is still not very fast at method dispatch. Looking at snit, we see that it is now very fast at method dispatch (nearly as fast as TclOO) but is still very slow to create objects.</p><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/Sarnold'>Sarnold</a>: Indeed <a class='mkup_a mkup_known' href='/page/Snit'>snit</a> is very slow at object instantiation, but building a snit-like system on top of <a class='mkup_a mkup_known' href='/page/XOTcl'>XOtcl</a>, namely <a class='mkup_a mkup_known' href='/page/xoins'>xoins</a>, give it far better creation times at the cost that method dispatch is slower. I do not know if <a class='mkup_a mkup_known' href='/page/William+Duquette'>William Duquette</a> is still working on a TclOO snit implementation - I hope it will succeed, because <a class='mkup_a mkup_known' href='/page/Snit'>snit</a> is really good for <a class='mkup_a mkup_known' href='/page/megawidget'>Megawidget</a>s and has a nice syntax that fits well upon <a class='mkup_a mkup_known' href='/page/Tcl'>Tcl</a>'s one.</p><p class='mkup_p'><a class='mkup_a mkup_known' href='/page/DKF'>DKF</a>: I'm working on two sets of (independent) improvements to TclOO that should make doing snit on top of it easier. Firstly, I'm doing something to make variables easier to use, so you can declare them once per class instead of once per method. Secondly, I'm trying to make submethods work (one of the neatest features of Snit). Apart from these, I suspect that the current method forwarding implementation is over-simplistic in its model; need someone to point me at a use-case case or two in order to figure out how to improve on that.</p><hr class='mkup_hr'><p class='mkup_p'>The script used to create the performance data is below. (Well, I actually did it interactively over a few runs, so I don't warrant that this script will really work...)</p><h3 id='256420a9344bbb0305616444b488a9767c9dcfdef8f4645cc3f78fc9b575c18f' class='mkup_h2'> Performance Analysis Script </h3><div class='sh_sourceCode'><button class='copybtn btn pull-right' data-clipboard-target='#mkup_code_8' title='Click to copy code snippet to clipboard'><span class='glyphicon glyphicon-copy' aria-hidden='true'></span></button><pre id='mkup_code_8' class='sh_tcl sh_sourceCode'>package require Tcl 8.5b1 # Compute Calls Per Second of a script # Note that this script is self-tuning; it prefers to execute a script for around a second proc cps {script} { # Eat the script compilation costs uplevel 1 [list time $script] # Have a guess at how many iterations to run for around a second set s [uplevel 1 [list time $script 5]] set iters [expr {round(1/([lindex $s 0]/1e6))}] if {$iters < 50} { puts "WARNING: number of iterations low" } # The main timing run set s [uplevel 1 [list time $script $iters]] set cps [expr {round(1/([lindex $s 0]/1e6))}] puts "$cps calls per second of: $script" } #-------------------------------------------------------------------------- puts "using Itcl..." package require Itcl 3.4 namespace path itcl class foo { variable x constructor {} { set x 1 } method bar {} { set x [expr {!$x}] } } foo f cps {f bar} delete object f cps {delete object [foo f]} delete class foo #-------------------------------------------------------------------------- puts "using XOTcl..." package require XOTcl 1.5.5 namespace path xotcl Class create Foo Foo parameter x Foo instproc init {} { my set x 1 } Foo instproc bar {} { my instvar x set x [expr {!$x}] } Foo create f cps {f bar} f destroy cps {[Foo create f] destroy} Foo destroy #-------------------------------------------------------------------------- puts "using TclOO..." package require TclOO 0.1 namespace path oo class create foo { constructor {} { variable x 1 } method bar {} { variable x set x [expr {!$x}] } } foo create f cps {f bar} f destroy cps {[foo create f] destroy} foo destroy #-------------------------------------------------------------------------- puts "using snit..." package require snit 2.1 snit::type foo { variable x constructor {} { set x 1 } method foo {} { set x [expr {!$x}] } } foo f cps {f bar} f destroy cps {[foo f] destroy} foo destroy #-------------------------------------------------------------------------- puts "using stooop..." # Must go last because it plays games with proc which might disturb the # performance of other OO systems. Note that stooop has both virtual and # non-virtual methods, with very different performance profiles. The virtual # ones are much more comparable in capability to other OO systems... package require stooop 4.4.1 namespace path stooop class foo { proc foo {this} { set ($this,x) 1 } proc ~foo {this} {} virtual proc bar {this} { set ($this,x) [expr {!$($this,x)}] } proc bar-nv {this} { set ($this,x) [expr {!$($this,x)}] } } set f [new foo] cps {$f bar} cps {$f bar-nv} delete $f cps {delete [new foo]}</pre></div> <p class='mkup_p'><a rel='nofollow' class='mkup_a' href='https://github.com/level44/design-patterns-in-tcl'>Simple examples of design patterns using TclOO <span class='glyphicon glyphicon-globe' aria-hidden='true'></span></a></p></div><hr><div class='mkup_centered'><table class='mkup_categories'><tr><td class='mkup_td'><a class='mkup_a' href='/page/Category+Object+Orientation'>Category Object Orientation</a></td><td class='mkup_td'><a class='mkup_a' href='/page/Category+Package'>Category Package</a></td></tr></table></div> </div> </div> <div class='row'> <div class='col-xs-12'> <div class='Footer'>Updated 2023-02-05 20:51:30</div> </div> </div> </div> <!-- jQuery library --> <script src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script> <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.0/js/jquery.tablesorter.combined.js'></script> <!-- Latest compiled JavaScript --> <script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js'></script> <script type='text/javascript' src='/scripts/nikit.js'></script> <script type='text/javascript' src='/scripts/sh_main.js'></script> <script type='text/javascript' src='/scripts/sh_tcl.js'></script> <script type='text/javascript' src='/scripts/sh_c.js'></script> <script type='text/javascript' src='/scripts/sh_cpp.js'></script> <!-- <script src='https://www.google.com/recaptcha/api.js'></script> --> <script src='https://hcaptcha.com/1/api.js'></script> <script>var clipboard = new ClipboardJS('.copybtn', { text: function(trigger) { return document.querySelector(trigger.getAttribute('data-clipboard-target')).textContent + '\n'; } }); sort_tables(); </script> </body> </html>