hide random home http://www.fmi.uni-passau.de/archive/doc/unix/perl/faq/2.11.html (Einblicke ins Internet, 10/1995)

How do I make an array of structures containing various data types?

How do I make an array of structures containing various data types?


    Well, soon you may not have to, but for now, let's look at ways to 
    synthesize these.

    One scheme I've invented uses what I call pseudoanonymous packages.
    This was motivated because I wanted an associative array of structures
    in which each structure contained not merely scalar data, but also lists
    and tables.   

    The table (read: associative array) is called %Active_Folders, whose
    key is the name of the folder, and whose values are, well, *logically*
    they're each a structure whose components look like this:

        $Current_Folder
        $Current_Seq  
        $Current_Line
        $Top_Line   
        $Incomplete_Read    
        $Folder_ID  
        $Last_Typed 
        @Scan_Lines
        %Scan_IDs 
        %Deleted 

    The way it works is that I only have one folder active at once.
    Those symbols as listed above are accessible from anywhere in the
    program.  The trick is that when I want to switch folders, I change
    what they point to!  You see, there's a package for each folder name
    that contains the real data.  So, it's not like I get to dereference

        $Active_Folder{$foldername}->$Current_Line

    or 
        $Active_Folder{$foldername}->$Scan_IDs{$msgnum}

    Although I'd like to.  I have to switch folders to $foldername first,
    and then access the individual fields directly.  The package isn't intuitable,
    which is why it's a pseudoanonymous one.

    Hm, I've this scary feeling that in Perl5, the last line will really read:

        ${$Active_Folder{$foldername}->Scan_IDs}->{$msgnum}

    or something, which is truly impossible for my brain to parse.  But I'm not
    real clear on it.  I get muddled up part way through whenever Larry explains
    how multiple levels of deferencing will work, and I'm not even sure I'll be
    able to get away with the above without setting up lots of pointers first.

    Anyway, here's the code that allows associative arrays of structures of 
    random data types.  I haven't done more than one level yet, although 
    surely you could embed the value of $Active_Folders{$folder} as a $Prev_Folder
    field in each, then do the right appropriate thing.

        sub gensym { 'gensym_' . ++$gensym'symbol } 

        sub activate_folder {
            local($folder) = @_;

            &assert('$folder',$folder);

            $Last_Seq = $Current_Seq;

            if (! defined $Active_Folders{$folder}) {
                $Active_Folders{$folder} = &gensym;
                push(@Active_Folders, $folder);
            }

            local($package) = $Active_Folders{$folder};

            local($code)=<<"EOF";
                {
                        package $package;
                        *'Current_Folder    = *Current_Folder;
                        *'Current_Seq       = *Current_Seq;
                        *'Current_Line      = *Current_Line;
                        *'Top_Line          = *Top_Line;
                        *'Scan_Lines        = *Scan_Lines;
                        *'Scan_IDs          = *Scan_IDs;
                        *'Incomplete_Read   = *Incomplete_Read;
                        *'Folder_ID         = *Folder_ID;
                        *'Last_Typed        = *Last_Typed;
                        *'Deleted           = *Deleted;
                    }
            EOF
            eval $code;
            $Current_Seq = $folder;

            &panic("bad eval: $@\n$code\n") if $@;
        }