C struct is Tcl!

This comes up every so often on comp.lang.tcl:

 Chris Nelson wrote:
 > For example, whereas I might write C like:
 >
 >     struct s {
 >        int foo
 >        char bar
 >        float grill
 >     }
 >
 >     s.foo = 1;
 >     s.bar = 'c';
 >     s.grill = 3.14159;
 proc struct { name thingys } {
     foreach thing $thingys {
        uplevel set $name.$thing \[ list \]
     }
 }

 struct s {
   foo
   bar
   grill
 }

 set s.foo 1
 set s.bar c
 set s.grill 3.14159

Of course, you probably don't just want to init the "struct" to nulls, but to reasonable values:

 proc struct { name thingys } {
     foreach { key value } $thingys {
        uplevel set $name.$key $value
     }
 }

 struct s {
   foo 1
   bar c
   grill 3.14159
 }

Tcl has no types, but if you want to create a typing convention and then use types in your struct it is only a matter of adding type to the foreach that now iterates key and value over $thingys. -PSE


How about this--values are optional; and there's a variable that lists all the fields in the structure:

 proc struct {name fields} {
     upvar $name srec
     foreach fld $fields {
         set fldn [lindex $fld 0]
         set fldv [lindex $fld 1]
         lappend srec $fldn
         uplevel set $name.$fldn [list $fldv]
     }
 }

 struct s {
    foo
    {bar 1}
    {pi 3.1415926}
 }

 foreach fld $s {upvar 0 s.$fld field; puts "s.$fld: '$field'"}

HJ

10-12-2002 escargo: I have my own clumsy implementation of something like this; there are some properties that I found desirable for such structures to have:

  1. Each structure can tell you its type.
  2. Each structure can tell you the names of its fields.
  3. It is possible to determine if the structure has a field with a specific name.
  4. There are ways to set and get each field from the structure by name.
  5. The structure is a value that does not depend on being assigned to a variable with a particular name.

Is there a C struct analog that has these properties?


So how do I create a linked list, as I would in C?

Ro: Well if you just want a list of objects you could just make a regular tcl list - they grow dynamically. Each element in the list could be a reference to an object... what are you trying to represent?

RS: Lists we have. The purpose of linked lists is often to allow insertion or deletion of elements, which our flat lists allow with linsert, lreplace and (probably most often wanted), lappend. You could simulate a linked list with an array, e.g.,

 set a(1,content) "hello world"
 set a(1,prev) 0 ;# "pointer" to previous
 set a(1,next) 2 ;# "pointer" to next element

... but I doubt whether that's more efficient than linsert/lreplace...

escargo: This does beg the question of how you would do a circular linked list using a tcl list, which is easy enough to do in C (or other language with pointers or references).

RS: Indeed, that's the strongest point against(?) flat lists, which is occasionally also raised in favor of Lisp. But iterating over a circular list may get you nowhere... However, to cycle over a list is easy in Tcl, and that is a frequent use for circular lists:

 proc cycle listName {
    upvar 1 $listName list
    set first [lindex $list 0]
    set list [concat [lrange $list 1 end] [list $first]]
    set first
 }

Lars H: Even better would be

 proc cycle listName {
    upvar 1 $listName list
    set first [lindex $list 0]
    set list [lreplace $list [set list 0] 0]
    lappend list $first
    set first
 }

since it (usually) allows the original object of the list to be modified in place and thus avoids allocating new storage for the list.

yajiang: in side tcllib struct::record usage above are all covered in this package struct::record. maybe you guys wanner take a look

https://core.tcl-lang.org/tcllib/doc/trunk/embedded/md/tcllib/files/modules/struct/record.md