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 $@;
}