X
Xiong Changnian
I am handling a number of complex objects -- the best way to build them
seems to be to have some of the HoH values be other objects. On the
other hand, some values just belong to the given object itself -- I call
these "whole-object data". (There is a graph theory slant to this but
it's not all about that. There's a game theory side, too.)
For example, a Map includes both Node and Edge objects. It also has data
that pertains directly to the Map -- for instance, it's NAME. I put all
the whole-object data in a hash with the key SELF. So, the name itself
would be accessed with:
$the_name = $somemap->{SELF}{NAME};
or, by method:
$the_name = $somemap->name;
Of course, the "name" sub uses the first syntax. I actually have only
one such sub; it's defined in the superclass. Every one of my objects
has a second-level hash key {SELF}{NAME}, so one accessor method serves
all.
Going down to an Edge object, it contains, as always, a SELF hash with a
NAME key, a COLOR key, and so forth. All this data pertains to the whole
object. The Edge also contains a primary key (on the same level as SELF)
called MATRIX; this points to an AoA (for reasons I'd hope are obvious).
So far, so fine. I have some accessor methods defined in the superclass
to which both Map and Edge (as well as others) belong, such as methods
to get at NAME and COLOR -- properties common to most of my objects. I
have other accessors defined in their respective
classes/packages/modules/files, such as "between":
$boolean = $someedge->between($i, $j);
which hits:
return $self-->{MATRIX}[$i][$j];
So far, so fine. To save these objects to disk, I use Data:umper. It's
not entirely compact but with indent and quotes turned off it's okay.
Best of all, I load back into the object simply by eval-ing the
datafile. Neither my Save nor my Load routine need to know anything at
all about the actual structure, so I can fiddle around with it freely.
It's even possible (though risky) to load a datafile created by an
earlier version of my script.
Data:umper works pretty well for this purpose but its output is not
especially readable; I can trade disk space for more readability by
setting Indent = 1 or 2 but matrices span hundreds of file lines that
way. So, I need to build a routine to display my Map object (hopefully
reusably, any of my objects) by printing to a report file in a pretty
format.
Ideally, I don't want to have to rewrite the report routine every time I
upgrade the object! The stupid way would be to have a rigid procedure in
which I took one thing at a time from the object and printed it. This
would depend on the structure of the object never changing -- bad.
My current approach is better. I do this (at several levels):
sub report_sets {
my @keys = sort keys %{ $ref->{SETS} };
foreach (@keys) {
&{"report_" . lc($_)} ($ref->{SETS}{$_})
or die ("No report subroutine for $_.");
};
};
So, I have a bunch of little subs, each of which is able to pretty
format a particular kind of data, each of which is named after the hash
key that points to that kind of data. These dig their way down until
they hit a sub that prints out one small chunk of data.
*THREE* problems:
(1) The sort keys operation puts, for example, MATRIX before SELF. For
readability in the report, I'd prefer a definite, predefined order for
the various subobjects and substructures -- I'd rather see the
whole-object data first before the big matrix. I suppose I can do this
with a custom sort routine.
(2) That there is a call to a subroutine by symbolic reference. To make
it work, I have to permit
no strict "refs";
for the duration of these shenanigans. I feel that's Bad in general; a
risky operation. Twenty years ago, I recall implementing a jump table
(in 8085 assembler) by constructing the destination address and shoving
it directly into the program counter via PCHL. Needless to say, it was
the first thing that broke.
(3) This seems to lead to a great number of very similar subs. This
suggests that I'm doing something stupidly (that is, not lazy enough).
My *thought* is to declare every level in the data structure as a
well-defined object, so Map will consist of a Self object, a Sets object
that contains ( Node objects which each contain a Self object ) and (
Edge objects which each contain a Self object and a Matrix object) and
so on. They all inherit from a superclass and Self, say, has its own
little method for pretty-reporting its own contents.
I don't know if I want to do this. Right now, each object has some
meaning beyond code implementation -- Maps, Nodes, Edges. This *thought*
of mine looks like 8 or more objects that all get rolled up into Map.
Each internal object will have to have its own package, its own file.
Will this be inefficient? Unmaintainable? Is there a better, lazier
approach?
Xiong
seems to be to have some of the HoH values be other objects. On the
other hand, some values just belong to the given object itself -- I call
these "whole-object data". (There is a graph theory slant to this but
it's not all about that. There's a game theory side, too.)
For example, a Map includes both Node and Edge objects. It also has data
that pertains directly to the Map -- for instance, it's NAME. I put all
the whole-object data in a hash with the key SELF. So, the name itself
would be accessed with:
$the_name = $somemap->{SELF}{NAME};
or, by method:
$the_name = $somemap->name;
Of course, the "name" sub uses the first syntax. I actually have only
one such sub; it's defined in the superclass. Every one of my objects
has a second-level hash key {SELF}{NAME}, so one accessor method serves
all.
Going down to an Edge object, it contains, as always, a SELF hash with a
NAME key, a COLOR key, and so forth. All this data pertains to the whole
object. The Edge also contains a primary key (on the same level as SELF)
called MATRIX; this points to an AoA (for reasons I'd hope are obvious).
So far, so fine. I have some accessor methods defined in the superclass
to which both Map and Edge (as well as others) belong, such as methods
to get at NAME and COLOR -- properties common to most of my objects. I
have other accessors defined in their respective
classes/packages/modules/files, such as "between":
$boolean = $someedge->between($i, $j);
which hits:
return $self-->{MATRIX}[$i][$j];
So far, so fine. To save these objects to disk, I use Data:umper. It's
not entirely compact but with indent and quotes turned off it's okay.
Best of all, I load back into the object simply by eval-ing the
datafile. Neither my Save nor my Load routine need to know anything at
all about the actual structure, so I can fiddle around with it freely.
It's even possible (though risky) to load a datafile created by an
earlier version of my script.
Data:umper works pretty well for this purpose but its output is not
especially readable; I can trade disk space for more readability by
setting Indent = 1 or 2 but matrices span hundreds of file lines that
way. So, I need to build a routine to display my Map object (hopefully
reusably, any of my objects) by printing to a report file in a pretty
format.
Ideally, I don't want to have to rewrite the report routine every time I
upgrade the object! The stupid way would be to have a rigid procedure in
which I took one thing at a time from the object and printed it. This
would depend on the structure of the object never changing -- bad.
My current approach is better. I do this (at several levels):
sub report_sets {
my @keys = sort keys %{ $ref->{SETS} };
foreach (@keys) {
&{"report_" . lc($_)} ($ref->{SETS}{$_})
or die ("No report subroutine for $_.");
};
};
So, I have a bunch of little subs, each of which is able to pretty
format a particular kind of data, each of which is named after the hash
key that points to that kind of data. These dig their way down until
they hit a sub that prints out one small chunk of data.
*THREE* problems:
(1) The sort keys operation puts, for example, MATRIX before SELF. For
readability in the report, I'd prefer a definite, predefined order for
the various subobjects and substructures -- I'd rather see the
whole-object data first before the big matrix. I suppose I can do this
with a custom sort routine.
(2) That there is a call to a subroutine by symbolic reference. To make
it work, I have to permit
no strict "refs";
for the duration of these shenanigans. I feel that's Bad in general; a
risky operation. Twenty years ago, I recall implementing a jump table
(in 8085 assembler) by constructing the destination address and shoving
it directly into the program counter via PCHL. Needless to say, it was
the first thing that broke.
(3) This seems to lead to a great number of very similar subs. This
suggests that I'm doing something stupidly (that is, not lazy enough).
My *thought* is to declare every level in the data structure as a
well-defined object, so Map will consist of a Self object, a Sets object
that contains ( Node objects which each contain a Self object ) and (
Edge objects which each contain a Self object and a Matrix object) and
so on. They all inherit from a superclass and Self, say, has its own
little method for pretty-reporting its own contents.
I don't know if I want to do this. Right now, each object has some
meaning beyond code implementation -- Maps, Nodes, Edges. This *thought*
of mine looks like 8 or more objects that all get rolled up into Map.
Each internal object will have to have its own package, its own file.
Will this be inefficient? Unmaintainable? Is there a better, lazier
approach?
Xiong