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

Hi PerlMonks !!

After 2 days of debug of a tool developed by me using Perl 5.10.1, I finally arrive here.

The issue:

In my perl code, I use several hash variables to store different info. The code misbehaved when I tested it on a different machine (but with same configuration as mine). The hash keys (when printed using Data::Dumper) were displayed within double quotes when the code was ran on different machine. On my machine, the hash keys appear without double quotes.

Because of the different hash keys format, I added deliberately double quotes ("") before accessing the hash using code as shown below:

key = "\"$key\"";

With above line added, the issue was resolved. So, this confirms the issue was due to hash keys having different form on different systems. However, the overall code still does not yield correct results on different machines and I am afraid it may take huge time to zero in to all such differences in the code. To the best of my understanding, I have not used anything apart from hashes, arrays (which are part of core perl) in the code. So I was expecting the code to be platform independent. I have listed below the modules used in my code below

use strict; use warnings; use Getopt::Long; use Cwd qw(abs_path); use Data::Dumper qw(Dumper); BEGIN { my @script_path_dirs = split('/',abs_path($0)); pop(@script_path_dirs); my $script_path = join('/',@script_path_dirs); # use lib $script_path; unshift @INC, $script_path; } use Voltrace;
In code portion shown above (copied from the beginning of the main code), Voltrace is my custom module which has some common subroutines. The Begin statement is only used to add the path of my custom module Voltrace.pm in @INC.

As the overall code is quite large, I will share it only if it is required to through more insight on what is happening. Any suggestion to resolve different perl behavior on different platform would be helpful.

I have also listed below few key points about platform/environment used:

Perl version and env used for development: 5.10.1 on RHEL 6.7 x86_64. Incremental testing and debug was done while development. The code works fine on my machine. Perl version and env used for testing on another machine: 5.10.1 on RHEL 6.7 x86_64 and 5.8.8 on RHEL 5.7 x86_64

As a workaround to avoid platform dependence, I have also tried copying the perl modules in the tool package and forcing tool to use the copied modules. This raises module incompatibility issues with other perl version as expected. This could have worked somehow if I could supply perl binary package along with my tool to the user to ensure complete independence from platform/environment. However, I am not sure if we can really achieve this or not (because my /usr/bin includes several other linux tools other than perl and so the perl binary linkage is not clear). Also, I am not sure if supplying perl binary is best way to get rid of platform dependence. Any insight would help. Thanks in advance !

Adding the subroutine which actually defines hash %pinList with which issue was observed

my %pinList = (); my $pinValFile = "Pin_Values.txt"; sub readPinValFile{ open(READ_PINVALS, $pinValFile) or die "[ERROR] Could not read Pin + Val file, $!"; print WRITE_RUN_LOG "[INFO] Reading Pin Values file for pin info f +ile->$pinValFile\n"; my @pinNames = (); my @pinMaxSDVs = (); my @pinMinSDVs = (); my $lineno=0; my $i=0; while(<READ_PINVALS>){ $i++; if($i > 1){ my $line = $_; $line =~ s/^\s*|\s*$//g; #To remove all leading and tra +iling blanks if($line ne ""){ my @pinWords = (); if($line =~ m/.*?,.*?,.*/){ @pinWords = split(',',$line); } elsif($line =~ m/.*?;.*?;.*/){ @pinWords = split(';',$line); } else{ $runLogErrCount++; print WRITE_RUN_LOG "\t\t[ERROR] Could not read pi +n info for $line at line $i\n"; next; } my $pin = $pinWords[0]; my $pinMaxSDV = $pinWords[1]; my $pinMinSDV = $pinWords[2]; $pin =~ s/^\s*|\s*$//g; #To remove all leading and +trailing blanks $pinMaxSDV =~ s/^\s*|\s*$//g; #To remove all leadin +g and trailing blanks $pinMinSDV =~ s/^\s*|\s*$//g; #To remove all leadin +g and trailing blanks if($pin ne ""){ if($pinMaxSDV eq "nil"){ $pinMaxSDV = ""; } if($pinMinSDV eq "nil"){ $pinMinSDV = ""; } $pinList{$pin} = [$pinMaxSDV,$pinMinSDV]; } else{ $runLogErrCount++; print WRITE_RUN_LOG "\t\t[ERROR] Could not read pi +n info for $line at line $i, incorrect pin name\n"; next; } } } } }

Replies are listed 'Best First'.
Re: Platform Dependence observed in Perl - Hash keys have different format
by Eily (Monsignor) on Mar 03, 2017 at 10:00 UTC
    The hash keys (when printed using Data::Dumper) were displayed within double quotes when the code was ran on different machine. On my machine, the hash keys appear without double quotes.

    There are two package variables in Data::Dumper that can modify this behaviour:

    $Data::Dumper::Quotekeys or $OBJ->Quotekeys([NEWVAL]) Can be set to a boolean value to control whether hash keys are quoted. A defined false value will avoid quoting hash keys when it looks like a simple string. Default is 1, which will always enclose hash keys in quotes.
    $Data::Dumper::Useqq or $OBJ->Useqq([NEWVAL]) When set, enables the use of double quotes for representing string values. Whitespace other than space will be represented as [\n\t\r], "unsafe" characters will be backslashed, and unprintable characters will be output as quoted octal integers. The default is 0.

    You should check the other modules you use, maybe one of them changes those package variables without resetting them, propagating the changed behaviour everywhere. BTW, to limit the effect of those variables you can use local.

    { local $Data::Dumper::Quotekeys = 0; print Data::Dumper \%hash; # No quote keys sub_from_other_module(); # No quote keys in the calls to Data::Dumpe +r from the other module } print Data::Dumper \%hash; # Quote keys sub_from_other_module(); # Quote keys as well

    The default behaviour is neither of the cases you have observed though (it's single quotes, not doubles, not none) so that's still surprising.

Re: Platform Dependence observed in Perl - Hash keys have different format
by haukex (Archbishop) on Mar 04, 2017 at 09:43 UTC
    The hash keys (when printed using Data::Dumper) were displayed within double quotes ...

    Please show, don't tell - post some sample input and the actual Data::Dumper output in <code> tags. See also How do I post a question effectively?

    Your description is a bit unclear on whether you mean (foo=>3) vs. ("foo"=>3), or ('foo'=>3) vs. ('"foo"'=>3). If it's the former, then Eily has already shown you the variables that control that behavior, although I would have to add that Data::Dumper is a debugging aid and not the best thing to output strings in a reliably consistent format - as long as its output is in Perl syntax it's doing its job.

    On the other hand, if it's the latter example, which I am thinking is the case, then I fully agree with Corion's post - the fact that you have to decide between commas and semicolons as separators means you're dealing with CSV files in different formats, so it's reasonable to assume that one input file might say foo;bar;quz and the other "foo","bar","quz". Using Text::CSV will take care of that for you.

    Just to point out one other thing: Your BEGIN { my @script_path_dirs = split('/',abs_path($0)); ... can, as far as I can tell, be replaced by the slightly more reliable use FindBin; use lib $FindBin::Bin;.

      Sorry for my delayed response and thanks for so many useful replies.

      Thanks Corion for your hint. The file Pin_Values.txt actually has a csv format and the tool opens the file using soffice. I now realize that I missed to check if CSV file (Pin_Values.txt) is being processed correctly by soffice on two machines. This could possibly be the reason since the machines might have different soffice setup. I can confirm this by Tuesday as I am currently out and not having access to my system.

      Hi haukex, thanks for your tips. Sorry for missing to go through process in pressure to resolve the error. To answer your query, I was referring to ('foo'=>3) vs. ('"foo"'=>3).

      Thanks Eily for sharing useful info about Hash key behavior. This will definitely help me in future. However, I did not change any settings that way and therefore I now suspect soffice to be the issue here.

Re: Platform Dependence observed in Perl - Hash keys have different format
by Anonymous Monk on Mar 03, 2017 at 09:04 UTC

    Your "workaround" means with 100% certainty the problem is your code

    Perl doesn't magically insert junk into hash keys that requires a programmer to guess at hash keys, that would be insane

      Thanks for the response.

      Could you please throw some light on why same code for defining a hash would yield hash key as only Key on one system and as "Key" on another? What could be possibly wrong with the code? I have added the subroutine in my post which actually defines the hash %pinList. On this hash I observed unexpected key format on different machine. Am I defining the hash incorrectly?

        Without seeing your input data, this is hard to tell. Your code seems to do some wonky CSV parsing here:

        my @pinWords = (); if($line =~ m/.*?,.*?,.*/){ @pinWords = split(',',$line); } elsif($line =~ m/.*?;.*?;.*/){ @pinWords = split(';',$line); }

        and then you write that value directly into the hash:

        ... $pin =~ s/^\s*|\s*$//g; #To remove all leading and t +railing blanks ... $pinList{$pin} = [$pinMaxSDV,$pinMinSDV];

        So my guess is that sometimes your CSV input data has double quotes around the pin and sometimes it does not.

        See Text::CSV_XS for CSV parsing.