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

Somebody must've surreptiously removed the caffeine from my caffeinated beverage because I just can't see why this doesn't work.

I simply wish to pass the hard-coded source hashref and a target hashref to a sub to measure lengths of strings from the first and populate the second. That part works great.

But I don't seem to have any visibility of the target hashref outside of measureHashrefLength even though it's declared in my main sub.

O Monks of Perl, enlighten me!

#! /home/gnu/bin/perl package main; use strict; use autouse 'Data::Dumper' => qw(Dumper); # prototypes sub readAdvisorTablesIntoHashref($); sub measureFieldLengths(); sub writeOutHashrefs(); sub writeOutHashref($$); #globals my $allActivity_hashref = { '1234-5678' => { 'Address' => "656 Poplar" ,'City' => "Monroe" ,'State' => "WI" ,'Zip' => "87654" ,'Phone' => "444-555-666 +6" } , '5757-4968' => { 'Address' => "656 Poplar" ,'City' => "Nightmare" ,'State' => "ND" ,'Zip' => "56532" ,'Phone' => "777-8888" } }; my $allActivity_fieldLength_hashref = undef; my $subHadErrors = 0; $subHadErrors = measureFieldLengths() unless( $subHadErrors); $subHadErrors = writeOutHashrefs() unless( $subHadErrors); exit(0); #------------------------------- sub measureFieldLengths() { print "entering measureFieldLengths\n"; my $errorHit = 0; measureFieldLength( "ACTIVITY", $allActivity_hashref, $allActivity_f +ieldLength_hashref); print "exiting measureFieldLengths\n"; return $errorHit; } #------------------------------- sub measureFieldLength($$$) { my ( $tableName, $tableName_hashref, $tableName_fieldLength_hashref) + = @_; print "entering measureFieldLength\n"; my $errorHit = 0; print "--inside measureFieldLength--input --". Dumper( $tableName_h +ashref); unless( $errorHit) { for my $Id ( sort{ $tableName_hashref->{$a} <=> $tableName_hashref->{$ +b} } keys( %$tableName_hashref)) { my $row_hashref = $tableName_hashref->{$Id}; for my $field_name ( sort{ $row_hashref->{$a} <=> $row_hashref->{$b} } keys( %$row_hashref)) { my $field_valu = $row_hashref->{$field_name}; $tableName_fieldLength_hashref->{$Id}->{$field_name} = 0; $tableName_fieldLength_hashref->{$Id}->{$field_name} = length( + $field_valu) if( defined( $row_hashref->{$field_name})); } } } print "--inside measureFieldLength--output --". Dumper( $tableName_f +ieldLength_hashref); print "exiting measureFieldLength\n"; return $errorHit; } #------------------------------- sub writeOutHashrefs() { print "entering writeOutHashrefs\n"; my $errorHit = 0; print "--inside writeOutHashrefs --input --". Dumper( $allActivity +_fieldLength_hashref); print "WT* why isnt global allActivity_fieldLength_populated ???? +\n"; writeOutHashref( "ACTIVITY", $allActivity_fieldLength_hashref); print "entering writeOutHashrefs\n"; return $errorHit; } #------------------------------- sub writeOutHashref($$) { my ( $tableName, $tableName_hashref) = @_; print "entering writeOutHashref\n"; my $errorHit = 0; unless( $errorHit) { for my $Id ( sort{ $tableName_hashref->{$a} <=> $tableName_hashref->{$ +b} } keys( %$tableName_hashref)) { my $row_hashref = $tableName_hashref->{$Id}; print $Id."\n"; my $outline = $Id; for my $field_name ( sort{ $row_hashref->{$a} <=> $row_hashref->{$b} } keys( %$row_hashref)) { my $field_valu = $row_hashref->{$field_name}; $outline = $outline.join('=', $field_name, $field_valu); } print $outline."\n"; } } print "entering writeOutHashref\n"; return $errorHit; }

Replies are listed 'Best First'.
Re: no visibility to global hashref ?!?
by Laurent_R (Canon) on Jul 20, 2014 at 09:11 UTC
    When you are entering the measureFieldLength subroutine, you are copying the argument $allActivity_fieldLength_hashref (which is undef at this point) into the $tableName_fieldLength_hashref variable. You are then populating the hash referred to by $tableName_fieldLength_hashref, but the global $allActivity_fieldLength_hashref variable remains undef throughout the process.

    You might want to return $tableName_fieldLength_hashref to the caller function when exiting the measureFieldLength and modify this function to assign that return value to the $allActivity_fieldLength_hashref global variable. Or, alternatively, work directly on the global variable within the subroutine (although this is far from being clean).

    In brief, you should either decide your variables are global and, in this case, you should not pass them around as arguments (this is not the best solution, but at least it would probably work the way you want), or you don't make them global and pass them around as arguments and return values (which would be considered a better solution). But don't mix the alternatives, that's what is getting you into trouble.

    Update: I would add that your program is difficult to read and to understand because your variable and function names are too long and too similar, and using CamelCase doesn't make your identifiers easy to read.

    Also, why are you using subroutine prototypes? Are you sure you understand and need them?

      I decided to go with returning the hashref being populated as a return value from measureFieldLength. Thanks for the replies, kerchunk
Re: no visibility to global hashref ?!?
by AnomalousMonk (Archbishop) on Jul 20, 2014 at 09:15 UTC

    Tangential to your main question (which I still don't understand), but the prototype of  measureFieldLength($$$) { ... } is declared too late to be effective.

    c:\@Work\Perl\monks>perl -e "package main; ;; use warnings; use strict; ;; sub foos () { foo(); } foos(); ;; sub foo ($$$) { print qq{hi from foo() singular \n}; } " hi from foo() singular

Re: no visibility to global hashref ?!?
by Anonymous Monk on Jul 20, 2014 at 09:01 UTC

    Here is some food for thought :)


    Just say no to globals, esp fake globals, no to subroutines that don't take arguments, no to subroutine prototypes and forward declarations , and no to return $errorHit, and no to overly wordy and long variable names

    Say yes to warnings, yes to subroutines that take arguments, yes to subroutines that return data values (not magic number error indicators), yes to subroutines that die on error, yes to concise and clear variable names

    Maybe

    Main( @ARGV ); exit( 0 ); sub Main { my $activity = { ... }; my $fieldLength = measureFieldLengths( $activity ); $fieldLength and writeOutHashrefs( $activity, $fieldLength ); }

    Maybe see Re: What are the most basic, generic aspects of programming?, Re: Perl Best Practices for naming variables, About the use of the plural form for the name of variables

    ## $allActivity_hashref $allActivity_fieldLength_hashref ## $allActivity_href $allActivity_fieldLength_href ## $activity_href $activity_fieldLength_href ## $activity_href $activityFieldLength_href ## $activity_href $fieldLength_href ## $activity $fieldLength ## $activity $activityLength ## %activity %activityLength #~ activity-of-'1234-5678' #~ activity-of-'peter'

    Maybe

    Maybe  $key and $val instead of  $field_name and $field_valu

    Maybe

    sub printTable { ... printRow( $table->{ $Id } ); } } ## end sub printTable

    Or maybe putting the important word first

    sub TableWrite { ... RowWrite( $table->{ $Id } ); } } ## end sub TableWrite

    Or to distinguish between packages and subs (packages CapsFirst subs lowerFirst )

    sub tableWrite { ... rowWrite( $table->{ $Id } ); } } ## end sub tableWrite
Re: no visibility to global hashref ?!?
by Athanasius (Archbishop) on Jul 20, 2014 at 06:10 UTC

    Hello kerchunk, and welcome to the Monastery!

    I’m sorry, I don’t understand what you are asking:

    But I don't seem to have any visibility of the target hashref outside of measureHashrefLength...

    I assume the “target hashref” is $allActivity_hashref, but I don’t find any reference to measureHashrefLength in the code shown?

    In any case, note that although you’ve commented the declaration of $allActivity_hashref, etc., under “globals”, variables declared with my are lexicals, not (package) globals (which are declared with our). A lexical variable declared at file scope, as here, is visible throughout the rest of the file, but not within code in other files using the same package.

    Please clarify where you want to access the “target hashref”, and how it fails to be visible.

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

      Ooof. replace "measureHashrefLength" with "measureFieldLength" in my explanation. And the source for measureFieldLength is $allActivity_hashref and the target is $allActivity_fieldLength_hashref. If one were to look in the sub measureFieldLength one could see it's reading rows from $allActivity_hashref and populating $allActivity_fieldLength_hashref. HTH, kerchunk

        So... How does it fail to be visible?

        Update: If 'it' is meant to be  $allActivity_fieldLength_hashref I think Laurent_R has put his finger on the problem below.

        Ooof. replace "measureHashrefLength" with "measureFieldLength" in my explanation.

        How 'bout you replace it yourself? Because you posted as a registered user (most desirable, IMHO), you can go back and edit your post. However, please be sure the edits are readily apparent via  <strike> ... </strike> or  <del> ... </del><ins> ... </ins> tags, or an "Update: ..." paragraph or paragraphs added at the end of the post — or both! Uncited changes to a post just make the replies of other monks seem incoherent. Please see Markup in the Monastery, Writeup Formatting Tips, etc.

Re: no visibility to global hashref ?!?
by LanX (Saint) on Jul 20, 2014 at 11:30 UTC