TIP #92: MOVE PACKAGE LOAD DECISIONS TO APPLICATION DEVELOPER =============================================================== Version: $Revision: 1.3 $ Author: Clif Flynt State: Withdrawn Type: Project Tcl-Version: 8.4 Vote: Pending Created: Monday, 13 May 2002 URL: https://tip.tcl-lang.org92.html Post-History: ------------------------------------------------------------------------- ABSTRACT ========== This TIP makes the loading of packages far more flexible, so as to better support their use by application authors in situations above and beyond those foreseen by the developer of the package. OVERVIEW ========== I believe that we've been misdirecting our efforts in solutions to the Package issue. * The modifications to /pkg_mkIndex/ give the library author (or package builder) the ability to define when a package will be loaded (immediate or deferred), which restricts an application developer to the decisions made by the library author. * If a package is built to be loaded immediately, it is loaded into the top-level namespace. This breaks previous tricks to force a package to load inside an existing namespace. These techniques limit the application writer to the behavior (and uses) envisioned by the package author and is counter to the concept that application developer best understands how they need a tool to perform for their application. The Tcl community, in particular, has grown largely because the tools have had applications far beyond those imagined by their initial developers. Moving the decisions about when and how to load a package from /pkg_mkIndex/ to the /package require/ command allows the application writer the freedom to find new styles of use that the package author may not have conceived. Being able to force an immediate load into the current namespace rather than always loading packages into the global scope provides support for lightweight object style data structures without the need for extensions like Incr Tcl, OOTcl, etc. Loading a package/namespace into the current namespace provides mechanisms for lightweight inheritance, and since namespaces can contain both code and data, loading a namespace multiple times (in separate namespaces) is a lightweight aggregation model. I do not propose that this power removes the need for full object oriented programming models within the Tcl community. However, I believe that putting the power to develop these lightweight models into the application developer provides the developer with a more versatile tool kit than they currently have. (One that I've been using for several years, with workarounds.) This proposal is to add new flags to the package require command, allowing an application developer to determine when and how to load a package. -current: Load the package into the current namespace rather than the global space. Implies immediate. -multiple: Allow loading multiple copies of this package, for use with /-current/ when the application programmer wishes to create multiple nested copies of a package. -immediate: Load immediately, rather than defer loading the package until needed. This is the default behavior with Tcl 8.3 and later. -defer: Load package when required. The default with Tcl 8.2 and earlier, or when /pkg_mkIndex -lazy/ used with Tcl 8.3. -exact: No change to this option. Requires an exact Major/Minor revision match to be an acceptable package. SCRIPT EXAMPLE ================ The code below implements a simple stack object that can be merged into other namespaces to create objects that contain individual stacks. package provide stack 1.0 namespace eval stack { namespace export push pop peek size variable stack "" proc push {val} { variable stack; lappend stack $val } proc pop {} { variable stack; set rtn [lindex $stack end] set stack [lrange $stack 0 end-1] return $rtn } proc peek {{pos end}} { variable stack; return [lindex $stack $pos] } proc size {} { variable stack; return [llength $stack] } } With this data structure available, the guts of a Tower of Hanoi puzzle becomes simple: namespace eval left { package require -current -multiple stack 1.0 namespace import [namespace current]::stack::* } namespace eval center { package require -current -multiple stack 1.0 namespace import [namespace current]::stack::* } namespace eval right { package require -current -multiple stack 1.0 namespace import [namespace current]::stack::* } proc move {from to} { ${to}::push [${from}::pop] } This creates 3 'objects' each of which contains a private stack with the stack methods. REFERENCE IMPLEMENTATION ========================== A reference implementation of the /-current/ and /-multiple/ flags has been created for Tcl 8.4a4 and is available at The implementation required these modifications to /generic/tclPkg.c/: * /Tcl_PackageObjCmd/ needs to be able to parse the new options and set the bitmapped flag. * /Tcl_PkgRequireEx/ is modified to accept a bitmapped flag instead of the /exact/ option. * The 0x0001 bitmap position is used to map for /exact/ preserving the existing behavior of the /Tcl_PackageObjCmd/ and /Tcl_PkgRequireEx/ functions. * These bitmapped flags are defined exact, current, and multiple: #define PKG_EXACT 0x01 /* Use the exact version - as used for exact */ #define PKG_CURRENT 0x02 /* Load into current namespace, not GLOBAL */ #define PKG_MULTIPLE 0x04 /* Allow loading multiple copies of a package */ * /Tcl_PkgRequireEx/ is modified to process the MULTIPLE and CURRENT flags. * The Tcl tests have been reworked to understand the new error returns, etc. Running "make tests" will accept the new code. Minimal testing has been done using pure Tcl packages. ------------------------------------------------------------------------- TIP AutoGenerator - written by Donal K. Fellows