Version 16 of Tcl Modules

Updated 2006-03-16 20:00:49 by escargo

Purpose: Discuss the purpose, and implementation, of TIP#189 [L1 ], TIP#190 [L2 ], and TIP#191 [L3 ] . Note this is something totally different from the Tcl Modules package.


See also Tcl Module creation script


See tarpack for an experiment in tar archives that are also sourceable Tcl Modules.


Could Tcl Software Libraries be relevant in discussing this topic?


LV I've seen people ask whether zip files will be supported as tcl modules; I myself am hoping to see starkits as tcl modules.


jmn 2005-09-13 ::tcl::tm::add can have unintuitive (IMO) results. tip189 clearly states that paths added last are 'looked at' first - but it doesn't make it clear that a package of the same version in a later path will 'override' the earlier entry in the 'package ifneeded' database.

This may be of concern if you are trying to create a local cache of packages with a fallback to your main repository on a (slower) network share - or if you are trying to force use of a particular module file during testing (without hacking at versions).

'package forget' won't help here - in contrast to the standard auto_path system where a path inserted into the head of $auto_path WILL allow loading of this package in preference to the one found later in the list (assuming either auto_path wasn't scanned prior to the addition, or you've called 'package forget' after the addition) .

Is this behaviour intended?

I think it'd be really nice to have some way (that works consistently for both module & auto_path systems) to override existing entries in the 'package ifneeded' database - for just those packages in a particular folder.

e.g a 'package scan <dir>' command might add just the packages found in <dir> - replacing any previous entries in the database.

Otherwise - some better introspection of the 'package ifneeded' database would be nice.. It's currently quite confusing to debug package loading issues so if you could do something like a 'package ifneeded *' and see what it holds - that might help.

Lars H: Do you mean something like this?

 proc package_ifneeded_* {} {
    set res {}
    foreach pkg [package names] {
       set L {}
       foreach ver [package versions $pkg] {
          lappend L $ver [package ifneeded $pkg $ver]
       }
       lappend res $pkg $L
    }
    set res
 }

Example:

 % join [lrange [package_ifneeded_*] 0 5] \n
 rcs
 0.1 {source /Library/Tcl/tcllib1.8/rcs/rcs.tcl}
 logger
 0.6.1 {source /Library/Tcl/tcllib1.8/log/logger.tcl}
 SOAP::Utils
 1.0 {source /Library/Tcl/tclsoap1.6.7/utils.tcl}

jmn Thanks yes - of course you're right.. the package command does provide enough basics to build your own view of the database as you require - I just think something similar to your snippet would be a nice inclusion to the standard distribution. While I should have known better and just built such a thing - I think for new users (or even just anyone a little unsure of how it all works) the package mechanisms have enough tricky subtleties that any extra introspection help that can be provided would be good.

Anyway.. this is an aside to the main issue I'm having: that I can't get the 'package require' system to use a package earlier in the module path if the package versions are the same. The theory may go that if the package versions are the same it shouldn't matter - but there may be administrative reasons to need this to behave properly - such as repository access speed.. or maybe a c-coded version to take higher precedence than a tcl-only version.

MG Perhaps an addition to the way [package require] works would help. For instance, if you could do

  package require -path [list "/path/to/thisfile" "/path/to/thatfile"] myPackage 2.0

to either have only those paths checked, or to have those checked first, followed by all the usual places, it might solve your problem. That would also allow you to [package require] a package which you know resides in a certain place, on its own, without having to add that path into your $auto_path (which is checked for all packages, slowing things down a little, as I understand it).

Another simpler solution to the C vs. Tcl versions is to just add another level to the version number. For instance, call a C version of a package version 2.0.2 and the pure-Tcl (slower) version 2.0.1, so that a [package require myPackage 2.0] would give priority to the C one.

LV So, does this mean that the order of auto_path doesn't control the order that package require searches for a package to load? It does seem that it would be useful if one could say

 package require /path/to/specific/version/of/extension

and only that would be used. That way, someone could test a new version of a package without it going into the live environment with possible negative consequences. Or one could code the above if there appeared to be some sort of problem with a package, to determine for certain whether a particular directory was the one causing a problem.

Lars H, 15 Oct 2005: One way to make sure a particular instance of a package is loaded would be to first explicitly source its pkgIndex.tcl file, like so:

 set dir /path/to/specific/version/of/extension
 source [file join $dir pkgIndex.tcl]
 package require packageName exactVersion

But mostly that is going the wrong way. A major reason package is useful is that it releives the programmer of having to know exactly where packages are located, so rolling that information back into its API would mess things up again.

escargo 14 Oct 2005 - Comparing the package mechanism to the executable search in Unix and Linux, maybe we need something like a which[L4 ] or whereis[L5 ] command (as subcommands of package).

In a way this is a kind of introspection of the execution environment.


tje Okay, I'm going nuts here...

I made a simple module 'foo-1.0.tm' under directory 'a', like this:

       /_path_/
               a/
                 foo-1.0.tm

I then started my tcl shell (8.5a4, a tclkit) and issued this command:

       ::tcl::tm::add /_path_/a

It shows up at the head of the list returned by ::tcl::tm::list now. So, what's the proper way to source this module without giving the absolute path? I've tried sourcing foo, foo-1, foo-1.0, foo.tm, foo-1.tm, and foo-1.0.tm, all to no avail.

ANSWER:

 package require foo 1

Category Deployment | Category Repository