megapkg structure extension

The megapkg structure extension provides rich structures, and capabilities beyond dict, and arrays. structure.so implements a custom Tcl_ObjType that caches some data for performance. It also is possible to use with eval safely. Performance is generally excellent.

It's available under a BSD-like license.

http://megapkg.googlecode.com/svn/trunk/csrc/structure/


Structure creation:

 set s [structure]

Alternatively named structures can be created. This is useful for widgets, and object systems.

 structure name

Structure keys:

Any characters can be used for keys in a structure (even binary). A custom hash table is used, so the NUL character is valid in keys.

Setting keys in a Structure:

Here are some examples of setting keys:

 $s -foo bar
 $s -key value -anotherkey value

Usage of a named structure is like this:

 structure foo
 foo -key value

Getting key values from a structure:

 set s [structure]
 $s -key value
 # This prints value
 puts [$s -key]

Locking:

The structure extension supports locking of keys, key creation, and structures as a whole.

Global locking:

This makes it so that no keys can be created or set, but key values may be retrieved as stated above.

 structure-lock $s
 structure-unlock $s

Locking keys to prevent modification:

 structure-lock-keys $s -key1 -key2 ...

 structure-unlock-keys $s -key1 -key2 ...

Locking key creation:

It can be useful for the construction of structures that are made available in a public API, to only allow certain keys to be set. By locking key creation new keys will not be created. This helps avoid errors. For example if the user ran the following:

 $s -backgrnd 

instead of:

 $s -background

The unfortunate result would be that -backgrnd is set instead of -background. Locking key creation prevents this error from occurring.

The usage is:

 structure-lock-creation $s

 structure-unlock-creation $s

Key traces:

It's possible to setup the evalution of a callback script, whenever a key is modified. If an error occurs in the callback it's reported during the setting of the value.

 set s [structure]

 $s -text Hello

 proc text.modified s { puts "You changed -text." }

 structure-trace-key $s -text [list text.modified $s]

It's allowable to free a structure while in a callback. The reference count of a structure is increased before the execution of any callback, and it will be freed upon the return of a callback, if structure-free was called in the callback.

Callbacks:

There can be layers of callbacks per key. Each layer is checked by creation order, and the first callback to return 1 results in the value being set. For example:

 $ tclkit8.5
 % load ./structure.so
 % set s [structure]
 % $s -key value
 % structure-key-callback
 wrong # args: should be "structure-key-callback structure-id key callback"
 % structure-key-callback $s -key [list callback $s -key]
 % proc callback {s key value} { if {"bob" eq $value} {return 1 ;#do set}; return 0 }
 % $s -key foo
 0
 % $s -key  
 value
 % $s -key bob
 1

The structure key callback may be removed with structure-remove-key-callback.

% structure-remove-key-callback wrong # args: should be "structure-remove-key-callback structure-id key callback"

Freeing a structure:

After some experiments it was decided that having reference-counted collection of a structure would be difficult to achieve with a custom Tcl_ObjType, and the performance might suffer. It's expected that structures will generally be retained for longer than the scope of a procedure. In cases of a procedure that requires a structure to have limited scope, an array can be used.

The patterns to free structures are:

 set s [structure]
 structure-free $s 

 structure foo
 structure-free foo

You can also do:

 set s [structure]
 rename $s {}

By George Peter Staplin


Comments:

So, the purpose of this structure data structure is to have variables which refer to groups of information - similar in to the purpose of Tclx's keyed lists, albeit with a differing syntax? Seems like an interesting idea. One thing I've always thought about was some sort of structure which could be used to map to C structs. I first saw an idea like that in Apple's Dylan language - one could, in their application, just reference a C header and a part of the Dylan build environment would dynamically create the appropriate glue connections so that your program could access the data structures (and functions!) appropriately.

George Peter Staplin: Tclx's keyed lists sound similar, though I doubt they have locking (I'll check out the code though :). I envision this as useful for creating widgets from the Tcl-level, that could be extended for megawidgets. It's also generic enough for almost anything. I view Tk_ConfigureWidget, and static (not the C keyword) widget structures in C as a limitation. I've implemented a few widgets in the past using gui.so (for exposing drawing, and the Tk C API) with a Tcl object system and multiple inheritance. While it worked, I found it to be overly complex, and then one day this "structure" idea occurred to me.

"megapkg structure extension" certainly seems interesting, yet I miss a clear explaination of specific advantages it might have relative to arrays and dicts. What application level problems are made easier with this extension? It would be nice if the head of the page contained such information. Also, I suggest a shorter name that perhaps refers to fewer things; to me the existing name suggests some sort of super-powerful way of managing Tcl packages from C code. Cheers, RT

LV RT, it is my understanding that "megapkg" is a package containing many different useful extensions. The structure package is one of the many packages in megapkg. The structure package is used for creating data collections of keys and values. Just as in C one might have:

 struct abc {
        int a;
        float b;
        char c[10]
 } myData;

it is my understanding with structure one can define:

 set s [structure]
 $s -a 123
 $s -b 3.1415
 $s -c "my text"

This data structure also has the ability to create the structure, then lock it so that some other code doesn't accidently add (or modify?) the structure; it reads as if it is a way to create semi-read only variables.