jweller1 has asked for the wisdom of the Perl Monks concerning the following question:

I've got some code that I've been trying to get to work but am failing pretty miserably at. I'm beginning to think it's just not possible to do this. Attached is a (possibly overly) simplified snippet of code

my @sciDbRows; my @hkDbRows; my @ancDbRows; my %dbFileArray = ( 'sci' => \@sciDbRows, 'hk' => \@hkDbRows, 'anc' => \@ancDbRows ); sub open1 { my $dbPath = '/home/user/SciPtrLoc.db'; use Fcntl 'O_RDWR', 'O_CREAT'; tie @sciDbRows, 'Tie::File', $dbPath, mode => O_RDWR | +O_CREAT or die; } sub write1 { my $part = 'sci'; my $ref = $dbFileArray{ 'sci' }; my @rows = @$ref; my $oneRec = "asdfg"; push(@rows, $oneRec); # does NOT work push(@{$dbFileArray{ $part }}, $oneRec); #does work $oneRec = "qwerty"; push(@sciDbRows, $oneRec); # does work } open1(); write1();

So I can push onto my tied file in some situations, but I'd like to get a better understanding what @{$dbFileArray{ $part }} actually is (an array? an array reference?) and also why I can't seem to assign it to a shorter and friendlier variable name, like @rows, so that later I can write

$rows[$index] = "new value";
instead of
@{$dbFileArray{ $part }}[$index] = "new value";

Replies are listed 'Best First'.
Re: Looking for some insight on Tie::File
by Athanasius (Archbishop) on Jan 09, 2016 at 03:30 UTC

    Hello jweller1, and welcome to the Monastery!

    The second method described by trizen above is the best option:

    my $ref = $dbFileArray{ 'sci' }; ... push @$ref, $oneRec;

    Just to confuse things :-), from Perl version 5.14 onwards you can omit the dereference:

    no warnings 'experimental::autoderef'; ... my $ref = $dbFileArray{ 'sci' }; ... push $ref, $oneRec;

    — but as that’s still “experimental,” it’s probably more trouble than it’s worth.

    I'd like to get a better understanding what @{$dbFileArray{ $part }} actually is (an array? an array reference?)

    %dbFileArray is a hash, so $dbFileArray{ $part } is the value associated with the key $part. In this case, $part contains the string 'sci', and the hash entry for that key was previously set via this assignment:

    my %dbFileArray = ( 'sci' => \@sciDbRows, ... );

    so the value returned by the hash lookup $dbFileArray{ $part } is \@sciDbRows, a reference to an array.

    Now, the important syntax to master here is @{...}, which is a dereferencing construct. It takes an array reference, and dereferences it to get the array it refers to. So in this case the expression @{$dbFileArray{ $part }} resolves to the array @sciDbRows. And that’s how pushing to @{$dbFileArray{ $part }} works — it’s really pushing to the array @sciDbRows.

    Note that this has nothing to do with the fact that @sciDbRows has been tied to a file. (BTW, in simplifying the example code you forgot to use Tie::File.) The key to understanding what’s going on here is to get a thorough grasp of references in Perl. Begin by studying perlreftut, then look at perllol and perldsc. I found Perl references hard to grasp at first, but with a bit of study and a fair amount of practice their use has become almost second nature. (Well, mostly!)

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Looking for some insight on Tie::File
by trizen (Hermit) on Jan 08, 2016 at 23:36 UTC

    Line my @rows = @$ref; copies the entire file into memory, therefore changing this array, doesn't affect the file. The solution is to create an alias or to use the reference instead.

    For example:

    my $ref = [1,2,3]; local our @row; *row = $ref; push @row, 4; print @$ref; # prints: 1234
    Or, simpler, push directly into @$ref:
    my $ref = [1,2,3]; push @$ref, 4; print @$ref; # prints: 1234

      I'll ask straight up... why in the name of all things good are you advising to use symbolic references? After I read that, I found it hard to identify how this even answers the OP's question. There's no explanation of deref'ing a hash reference, and your use of local our ... seems way off as well.

      I very rarely take issue with posts here, but unless you wrote the code that OP has displayed, what you're saying is pretty bad advice.

        I'll ask straight up... why in the name of all things good are you advising to use symbolic references? After I read that, I found it hard to identify how this even answers the OP's question.

        Try it and you will see, it lets the OP use @array instead of $ref