in reply to Re: Dotted hash access
in thread Dotted hash access

I can buy your arguments if we're talking about completely general nested data structure access, but that's not what I'm after. I really do have a deeply nested structure, which I am completely specifying -- so I have no worries about $location or $b containing the separator, because they're field names. My values could very well have weird characters in them, but I'll never have anything unexpected in the "path" of a value. (True, a field name like $location could easily be coming from an external source, but I have to scrub them for sanity well before reaching this code anyway.)

$cost = $h->{$location}{$building} wouldn't work for me. The structure contains many more things than just Locations, and a location has much more data associated with it than a set of Buildings. So I don't want to accidentally get the wrong value back if I have a location name that happens to coincide with some other field name. (Perhaps I should give a more detailed dump of a data set?)

My approach differs from Perl4's because mine can be used hierarchically, unlike $;. So I am free to do

$locinfo = $h->{"Locations.$location"}; count_totals($locinfo->{"Resources"}); compute_upkeep($locinfo->{"Buildings"});
or whatever.

Replies are listed 'Best First'.
Re^3: Dotted hash access
by brian_d_foy (Abbot) on Nov 25, 2004 at 19:24 UTC
    If that's the case, why don't have have a class that represents and provides access to the data structure? You can make the interface very simple without creating a bunch of new syntax that you will have to explain to everyone who looks at the code. Try a class setup: Thingy HAS Buildings HAS Locations: You leave everything in your big hash, but when you need something, you ask for it through a method which gives you a reference to that branch of the data structure.
    $location = $thingy->get_location( $l );
    That method looks at the big data structure, pulls out the reference which is the value for the key $l (which has no restrictions on its characters), blesses it as the mini-class Location, and returns it. It's the same old reference, there is no copy, but you can call methods on it. Not only that, it's easy to see what it's doing because there isn't a lot of things happening at that level.
    $building = $location->get_building( $b );
    That's the same thing, called on the previous mini-object. All the data is still in the big data structure, but you have this hook into it because the reference $building is blessed into the Buidling class. Again, it's the same old reference that's in the data strucutre, but it now knows how to respond to method calls. Or, you can do this in one step.
    $building = $thingy->get_location( $l )->get_building( $b ); #or $building = $thingy->get_building_by_location( $l, $b );
    Or
    $cost = $thingy->get_location( $l )->get_building( $b )->cost; $totals = $location->get_totals; $upkeep = $building->get_upkeep;
    If you want to iterate through everything:
    foreach my $l ( $thingy->all_locations ) { foreacn my $b ( $b->all_buildings ) { $b->set_cost( $b->cost + 1 ); } }
    You can define all sorts of other iterators, visitors, and cool things. You don't have to know anything about the data structure. You have a lot of flexibility with this approach, and it uses vanilla Perl syntax that people can read about it in books and in the documentation. You don't have to create any new way to do thing, which means you don't have to create new logic or new bugs. If you want iterators, you can create those yourself inside the class. I talk about all sorts of these things in The Perl Review 0.5.
    while( my $location = $thingy->next_location ) { ... }
    So don't create a new dialect, which just adds to the complexity of your code. You should code not so you understand it, but so other people will understand. :)
    --
    brian d foy <bdfoy@cpan.org>