Oliver Wong said:
Sounds like what perl calls "hash", Java calls Map. So to implement a "hash
or hashes", use a Map of Map. E.g.
Map<KEY_TYPE,Map<KEY_TYPE,VALUE_TYPE>> names = new
Map<KEY_TYPE,Map<KEY_TYPE,VALUE_TYPE>>();
names.get(branch).put(account, 0);
Here "names.get(branch)" will return null. One needs to add
code to create another map as the value of "get(branch)".
In Perl, this is not neccessary.
Perl has a feature called "autovivifications", that will
assure that "$name{$branch}" exists and is a map. The script
use Data:
umper;
$names{"branch"}{"account"} = 123;
print Data:
umper:
umper(%names), "\n";
prints
$VAR1 = 'branch';
$VAR2 = {
'account' => 123
};
It is not neccessary to build the map structure in Perl.
The script essentially consists only of the single line
»$names{"branch"}{"account"} = 123;«. The other two lines
are there only to get the debug output. Possibly a slight
variation makes this even clearer:
use Data:
umper;
$names->{"branch"}->{"account"} = 123;
print Data:
umper:
umper($names), "\n";
prints:
$VAR1 = {
'branch' => {
'account' => 123
}
};
So both maps are "magically" created in Perl. One does not
have to tell Perl that the reference $names is a reference to
a map, which actually needs to be allocated and then have its
address written into »$names«, before it can be assigned to.
The single line »$names->{"branch"}->{"account"} = 123;« will
suffice.
Here is a simple example of autovivification in a special
case for Java:
class NumericMapUtils
{ public static <D> void addTo
( final java.util.Map<D,java.lang.Integer> map, final D d, final int i )
{ map.put( d, i +( map.containsKey( d )? map.get( d ): 0 )); }}
Now one can declare a map:
final java.util.Map<java.lang.Integer,java.lang.Integer> map =
new java.util.HashMap<java.lang.Integer,java.lang.Integer>();
And then add 7 to its entry 4:
NumericMapUtils.<java.lang.Integer>addTo( map, 4, 7 );
If the entry 4 does not exist yet, it will be created (hence,
"autovivification") with an initial value of 0 by »addTo«.
Perl is even smarter: By the usage »...{"account"} = 123;«
it was able to figure out that here not "0" is needed as the
initial value, but another map instead.
Here is an excerpt from a knowledge base I wrote in Perl:
sub set($$$$$)
{ push @{ $::assertion }, [ ${$_[ 0 ]}, ${$_[ 1 ]}, ${$_[ 2 ]}, ${$_[ 3 ]}, $_[ 4 ] ];
push @{ ${$_[ 0 ]}->{'%'}}, $#$::assertion;
push @{ ${$_[ 1 ]}->{'{'}}, $#$::assertion;
push @{ ${$_[ 2 ]}->{'|'}}, $#$::assertion;
if( !( defined( $_[ 4 ] ))){ push @{ ${$_[ 3 ]}->{'}'}}, $#$::assertion; }}
It makes use of autovivification (which also exists for
arrays) and would be much more complicated to write without
autovivification. I am currently rebuilding this system in
Java and writing the corresponding code takes much longer in
Java. The programmer needs to explain all the details to Java
that Perl is able to grasp itself from the code the programmer
writes.
When I write »push @{ ... }«, Perl knows that »...« needs to
be a reference to an array that needs to be allocated, if it is
not yet there. Java gives you the garbage collector, so you do
not have to release objects, Perl gives you autovivification,
so that you do not even have to allocate them.