Version 60 of Jim

Updated 2005-04-06 01:26:16

What: Jim

 Where: http://jim.berlios.de/
 Description: Small footprint implementation of Tcl.  It is a
        work in progress, but as an interpreter, it already is able
        to run many tcl scripts.  Note this is NOT an attempt to
        implement a Tcl 7.x interpreter - Tcl 8.5 features already
        are present in Jim.
 Updated: 02/2005
 Contact: See web site

Recent Changes of this page

  • 21Mar2005 - Added uptodate benchmarks between Jim compiled with -O3, -O2, -Os. Tcl8.4, Tcl8.5 and Tcl7.6. SS
  • 21Mar2005 - List of commands implemented updated (note that there is scan now!). SS

Index

Features

  • Jim is small, the full executable is around 70k compiled with -Os
  • Jim is modern, it already includes {expand}, dicts, and new features not implemented in Tcl 8.5.
  • There is syntax for dicts. In Jim the form a($index) is syntax sugar for dict get/set operations. This means that Jim's arrays (dictionaries) are a first class type that you can pass as argument to a procedure, return from a procedure, and so on. Example:
 Welcome to Jim version 0.50, Copyright (c) 2005 Salvatore Sanfilippo
 0 jim> set a(foo) 10
 10
 0 jim> set a(bar) 20
 20
 0 jim> puts $a
 foo 10 bar 20
 0 jim> set b "1 2 3 4"
 1 2 3 4
 0 jim> puts $b(1)
 2
  • Jim has lambda with gargabe collection.
  • Every kind of Jim procedure is also a closure, thanks to support for static variables.
  • Jim's static vars are trivial to use. Simply proc can accept optionally a statics list after the usual arguments list. Example:
 0 jim> proc foo {increment} {{value 0}} {incr value $increment}
 0 jim> foo 1
 1
 0 jim> foo 1
 2
 0 jim> foo 1
 3
 0 jim> foo 10
 13
 0 jim> foo 10
 23
  • If a static var is not initialized explicitly the initial value is taken from the variable name with the same name in the local context:
 0 jim> set x 10  
 10
 0 jim> proc bar {} x {puts $x}    
 0 jim> bar
 10
  • Closure, Garbage collection, lambdas, makes Jim the first Tcl implementation where it's trivial to build the Paul Graham's well known accumulator function:
 # Write a function foo that takes a number n and returns a function that
 # takes a number i, and returns n incremented by i. Note: (a) that's number,
 # not integer, (b) that's incremented by, not plus.

 proc accumulator n {
    lambda increment n {
        set n [expr {$n+$increment}]
    }
 }

 set f [accumulator 100]
 puts [$f 10]
 puts [$f 20]
 puts [$f 1.25]

The output is

 110
 130
 131.25

RS: As Jim has prefix operators, I'd write it like this:

 proc accumulator n {
    lambda increment n {set n [+ $n $increment]}
 } 

Other Jim documentation in this Wiki

Commands already implemented

 . lsort [info commands]
 * + - / append break catch collect concat continue debug dict env error
 eval exit expr finalize for foreach format getref global if incr info
 join lambda lambdaFinalizer  lappend lindex linsert list llength lmap
 load lrange lreverse lset lsort proc puts ref rename return scan set
 setref source split string subst switch time unset uplevel upvar while

Note that the format command is ... virtual, a very subset for now. Also info may not have everything, but important stuff are mostly there.

  • Jim has a simple to use references system to build arbitrary linked data structures, with garbage collection. The reference system can be also used to add automatic memory managment to every other kind of object. For example Jim's lambda use the reference system for garbage collection, and so will do the Jim's OOP system that's under development.
  • Jim has dynamic loadable libraries. Initial libraries about win32 API, win32 OLE, POSIX, and ANSI/C file I/O, are present in the Jim's source distribution.

Benckmarks

Here is a comparison of a recent (21 Mar 2005) version of Jim. Note that Jim appears three times, compiled with -O3, -O2, -Os.

 Jim benchmarks - time in milliseconds
                     Jim-O3 Jim-02 Jim-Os  8.4.9  8.5a3  7.6p2        
        sieve [dict]    580    650    680      F    499      F 
     [for] busy loop    190    250    230    315    325   3531 
               sieve    850    950    950    258    236   1213 
            heapsort    590    600    620    159    148      F 
               upvar    430    460    450    359    359    691 
              expand    170    180    180      F    184      F 
        dynamic code    600    610    610    725    419    445 
        nested loops    700    710    690    231    291   2795 
              repeat    490    500    560   3014   2667   3752 
    wiki.tcl.tk/8566    700    780    760    426    261      F 
          mini loops    370    390    420    282    337   3440 
                 ary    630    710    720    313    297    770 
           PI digits    930    990   1030    484    408      F 
 dynamic code (list)    180    160    170    198    301    457 
   [while] busy loop    380    430    440    254    276   3588 
       fibonacci(25)    550    570    570    299    287   1316 
              rotate     70     80     80      F      F      F 

For now the work goes in the direction of making Jim more capable and not faster. Once the expected feature level will be reached I'll try to make it faster, being the current speed acceptable for most Jim-target purposes IMHO, at least for this initial stage!

Note that if you plan to write very dyamic code, with a lot of eval/upvar, Jim is probably currently the faster of the three. (See the repeat test).

The source for the benchmarks can be found at [L1 ]

License

Jim is under the APACHE 2.0 license, this means that it's GPL compatible, but like Tcl itself can be used in commercial software without need to distribute the modified source code. In one word Jim is free for both the opensource and the commercial world!.

Commercial Support

Salvatore Sanfilippo, the main author of Jim, will be glad to support in the extension and integration of Jim in embedded systems, as scripting language of existing application, and any other need. For more information write an email to antirez at gmail dot com.

Interested in Jim?

If you want to stay informed about Jim you can subscribe to the jim-devel mailing list. There is a web form to subscribe at https://lists.berlios.de/mailman/listinfo/jim-devel . If you are a developer and want to help check the Jim development page, that is the way Jim developers try to organize the work.

Here is a place for your comments about Jim


02mar05 jcw - Jim is fascinating. Great engineering, IMO!

I've got an experimental reader for Metakit database files as well as a tiny Zlib decompressor based on the Vlerq project I'm working on. Should make it possible to support R/O starkits with very low footprint overhead (my guesstimate would be 25..35 Kb on top of Jim itself). The main issue is how to handle opens and globs and reads from things which are not files. As far as I can see, Jim has no I/O yet. Might be an idea to use a lightweight OO model ("$file read") so one can create objects that end up reading from a starkit. Could also be memory-mapped. Lots of ways to go from here...


SS 3-Mar-2005: Thanks for the good words! I followed the metakit discussion on the Feature Request thread but fortunately my lack of skills in metakits makes me unable to help from this point of view, with the exception that I can focus on the I/O extensions ASAP. For the OO, there will be Odys (with some change probably) integrated into the core (assuming I'll be able to implement it in max 1000 lines of code, otherwise I'll be forced to make it an extension, even if the Jim model is "little core, all extension" I really consider the OOP system to be a core language feature). Btw... I'm thinking that for startkits in unix-land another strategy that's possible to follow is to put POSIX I/O things into the jim-posix extension, and write an higher level interface directly in Tcl.

Yes, the Odys object system could work. No need for POSIX I/O if you *only* want to read from a starkit (which could make Jim secure, sort of). The code I have supports mem-mapped access on Windows, Linux, Mac OS X. -jcw


Googie - How about speed? Are there any benchmarks available? I'm interested much in expr operations, but also others.

SS 2Mar2005: Hello Googie! Jim is currently slower than Tcl, but is faster than Tcl 7.6.


PT 3-Mar-2005: Jim supports dynamically loaded extensions. One of them supports a certain degree of COM automation under windows....

 load jim-win32com
 set ie [ole32 create InternetExplorer.Application]
 ole32.invoke $ie Navigate2 http://wiki.tcl.tk/jim
 ole32.invoke -put $ie Visible True

The above script results in Internet Explorer displaying this page.


SS 3-Mar-2005: That's cool! And is all merit of Pat. Also there is a start of win32 API binding. To hack with it:

  load jim-win32.dll
  info commands win32.*
  ...

SEH -- 2005/03/01 -- I've often thought that a good way to demonstrate Tcl's power and to smooth the process of Tcl's development and improvement would be to control the compiling of Tcl and its extensions primarily with Tcl itself (I'm sure I'm not the only one). A mostly pure-Tcl build process would significantly lower core development participation barriers.

Of course there is the bootstrap problem, which I thought might be solved by using Ettcl or TinyTcl. Now Jim provides an intriguing new option.

A one-file implementation of a basic set of Tcl commands ought to be a great tool for bootstrapping problems. If a script could be run using Jim to compile a basic tclsh, then that tclsh could be used to control the rest of the compiling and packaging process.

A viable Jim -> tclsh -> cc compile toolchain that could conceivably replace existing bash -> m4 -> autoconf -> automake -> make -> cc toochain nightmares might greatly widen the appeal of Tcl in the software development world.

SS 5Mar2005 - Update: in order to explore the proposal of SEH as well as the ability to run simple starkits with Jim, I'm working on a very simple Jim extension called AIO (Ansi I/O) that exports ANSI C file capabilities to Jim with a OOP Interface (and it is very simple to provide Tcl file API compatibility via some glue procedure). The intial version is on the CVS, people interested in this issue my follow the thread in the Feature Request at http://developer.berlios.de/feature/?group_id=3204 .

On the last days Jim reached a better shape, there are more core commands, it's more binary safe (now all the parsers are binary-safe), and robust. Also the exported C API is more complete.

That's how the AIO extension looks like:

 load jim-aio.so
 set f [aio.open /etc/passwd]
 set f2 [aio.open /tmp/FOOBAR w]
 while {[$f gets line] != -1} {
     $f2 puts "~~ $line ~~"
 }
 $f close
 $f2 close

Very similar to cfile.


SEH, that is an excellent idea! I would love to see something like this - davidw.

It also looks very interesting to me :) SS.

SEH -- Jim + Critcl might be the basis for a dandy cross-platform autoconf replacement.


LV Anyone have a table comparing features of Tcl and Jim, so that one can more easily understand the differences?

RS Jim is a rapidly moving target, but here's a quick sketch of what I can think of at the moment (see also Jim development for further differences):

On Jimulation I've started to "back-port" some useful Jim features to pure-Tcl, but most recently Jim seduces me to do even C fun projects... see below.


RS: See also Tiny OO with Jim - Jimulation / 2005-03-20: Here's this evening's fun project - adding an ** operator to jim.c (only added lines shown - "Doctor, somehow writing C doesn't hurt any more" :):

 #include <math.h>
 ...
 #define JIM_EXPROP_POW 34
 ...
   {"**", 250, 2, JIM_EXPROP_POW},
 ...
 (in ExprCheckCorrectness() :)
       case JIM_EXPROP_POW:
 ...
 (before Jim_EvalExpression:)
 static jim_wide ipow(jim_wide a, jim_wide b) {
   jim_wide i, res = 1;
   if ((a==0 && b!=0) || (b<0)) return 0;
   for(i=0; i<b; i++) {res *= a;}
   return res;
 }
 (in Jim_EvalExpression() :)
 ...
        case JIM_EXPROP_POW:
 ...
case JIM_EXPROP_POW
wC = ipow(wA,wB); break;
 ...
           case JIM_EXPROP_POW: dC = pow(dA,dB); break;

Interactive testing:

 Welcome to Jim version 0.50, Copyright (c) 2005 Salvatore Sanfilippo
 CVS ID: $Id: 13693,v 1.61 2005-04-06 06:00:44 jcw Exp $
 . expr 0**0
 1
 . expr 0**1
 0
 . expr 123**0
 1
 . expr 2**3
 8
 . expr 2**3.
 8.0
 . expr 3.**2
 9.0
 . expr 2**0.5
 1.4142135623730951

And that was on my old W95 box, with gcc/egcs-2.91.57 :)

Known problem (should result in -16):

 . expr -2**4
 16

Looks like unarys are done before binarys, no matter what priority I give them. Also, here's a bug report:

 . expr -(1+2)
 Runtime error, file "?", line 1:
    Invalid expression

SS Thanks Richard! I'll add ** ASAP. The unary minus is not a bug it's not implemented at all! When you use -2**4, "-" is just used as (-2)**4. While -(1+2) generates an error because - is only binary so an argument is missing. This will be fixed together with many other expr issues once my flu goes away ;).


RS was heard to aphorize, "Jim - because even simplicity can get simpler".


I'm having problems compiling the extensions to Jim under Mac OS X.2.8. I get the following when I try to do a "make aio":

 ld -G -z text -o jim-aio-1.0.so jim-aio.xo -ldl -lc
 ld: unknown flag: -G
 make: *** [jim-aio-1.0.so] Error 1

I do have dlcompat installed and am using gcc 3.3. BMA

Category Language, Category Jim