Perl - New Hash item with modified data, sourced from a feeder hash that sourced another entry, clobbers the first entry

Viewed 64

I'm trying to add a hash entry and a new, updated hash entry that are sourced from the same feeder hash and original data.

However, when I update the data for the 2nd entry... it clobbers the original entry... even though that data wasn't changed... it can only have changed due to both being assigned from the same feeder hash entry.

Here's a sample subroutine from a test program that I created to test this issue - it uses Tk for output...

sub hash_issue {
    my %feeder = ();
    my %global = ();
    my %personal = ();

    my $key = 'John';
    my $new_key = 'Johnathan';

    $feeder{$key}{First_Name} = 'John';
    $feeder{$key}{Last_Name} = '';
    $feeder{$key}{Address} = '123 Main Street';
    $feeder{$key}{City} = 'Springfield';
    $feeder{$key}{State} = '';
    $feeder{$key}{Zip} = '';
    $feeder{$key}{Is_Registered} = 0;
    
    $global{$key} = $feeder{$key};
    $main->Output->Append("First Name = $global{$key}{First_Name}  Last Name = $global{$key}{Last_Name}  Address = $global{$key}{Address}  Registered = $global{$key}{Is_Registered}\r\n");
    $global{$new_key} = $feeder{$key};
    $global{$new_key}{First_Name} = $new_key;
    $global{$new_key}{Is_Registered} = 1;
    $main->Output->Append("First Name = $global{$key}{First_Name}  Last Name = $global{$key}{Last_Name}  Address = $global{$key}{Address}  Registered = $global{$key}{Is_Registered}\r\n");
    $main->Output->Append("First Name = $global{$new_key}{First_Name}  Last Name = $global{$new_key}{Last_Name}  Address = $global{$new_key}{Address}  Registered = $global{$new_key}{Is_Registered}\r\n");
}

Here's the output...

First Name = John Last Name = Address = 123 Main Street Registered = 0

First Name = Johnathan Last Name = Address = 123 Main Street Registered = 1

First Name = Johnathan Last Name = Address = 123 Main Street Registered = 1

(Extra Lines added to clean the post...)

How can I modify this to keep from clobbering the original entry... The REAL code contains more key to the sub hash.

2 Answers

Your problem is here

$global{$new_key} = $feeder{$key};

This only copies a reference. You need to clone your data if you want an actual copy.

use Clone qw( clone );
$global{$new_key} = clone( $feeder{$key} );

Please investigate the following code snippet for compliance with your problem.

My understanding from your description is that you try to create new hash %global (with $new_key as a key) with copy of values of hash %feeder and then alter a few values in it.

NOTE: a declaration of %global variable inside subroutine somewhat confusing

use strict;
use warnings;
use feature 'say';

hash_issue();

sub hash_issue {
    my(%feeder, %global);

    my $key = 'John';
    my $new_key = 'Johnathan';

    my @fields = (
                    'First_Name',
                    'Last_Name',
                    'Address',
                    'City',
                    'State',
                    'Zip',
                    'Is_Registered'
                 );
    my @values = (
                    'John',
                    '',
                    '123 Main Street',
                    'Springfield',
                    '',
                    '',
                    0
                 );

    @{$feeder{$key}}{@fields} = @values;

    @{$global{$new_key}}{@fields} = @{$feeder{$key}}{@fields};

    speak_out($key, \%feeder);
    speak_out($new_key, \%global);

    $global{$new_key}{First_Name} = $new_key;
    $global{$new_key}{Is_Registered} = 1;

    speak_out($new_key, \%global);
}

sub speak_out {
    my $key  = shift;
    my $data = shift;

    say "
        Key = $key
        ------------------------------------
        First Name = $data->{$key}{First_Name}
        Last Name  = $data->{$key}{Last_Name}
        Address    = $data->{$key}{Address}
        Registered = $data->{$key}{Is_Registered}
    ";
}

Output


        Key = John
        ------------------------------------
        First Name = John
        Last Name  =
        Address    = 123 Main Street
        Registered = 0


        Key = Johnathan
        ------------------------------------
        First Name = John
        Last Name  =
        Address    = 123 Main Street
        Registered = 0


        Key = Johnathan
        ------------------------------------
        First Name = Johnathan
        Last Name  =
        Address    = 123 Main Street
        Registered = 1

Reference: Perl - Slices

Related