views:

164

answers:

3

Related/possible duplicate: http://stackoverflow.com/questions/1263943/why-do-i-get-uninitialized-value-warnings-when-i-use-datemanips-sortbylength

This block of code:

my @sorted_models = sort { 
    UnixDate($a->{'year'}, "%o") <=>
    UnixDate($b->{'year'}, "%o") 
} values %{$args{car_models}};

kept generating the following error warning:

Use of uninitialized value in length at /.../Date/Manip.pm line 244.

Date::Manip is a CPAN module. And line 244 of Date::Manip is found within the following block of code:

# Get rid of a problem with old versions of perl
no strict "vars";
# This sorts from longest to shortest element
sub sortByLength {
    return (length $b <=> length $a);
}
use strict "vars";

But then including this (printing out the actual Unix Date value to the console in the logger) before the block of code to sort the values:

foreach (values %{$args{car_models}}) {
    $g_logger->info(UnixDate($_->{'year'},"%o")); 
}

removed the errors warnings entirely. Why? And what is a good fix instead of doing all these logging statements?

NOTE: None of the sorted values are undefined because when I printed them out in the logger, I could see that every one of them had a numerical value.

A: 

So I added that line of code to dump my data:

 my @sorted_models =    sort { $g_logger->info(Dumper{a=>$a,b=>$b});
                        UnixDate($a->{'year'}, "%o") <=>
                        UnixDate($b->{'year'}, "%o"); }
                        values %{$args{car_models}};

I was able to dump $a and $b ONCE, then I got the error like >50 times, followed by a dump of $a and $b for 20 or so times (I have 10 elements in my array)

Kys
Wait this isn't an answer. I meant to write it as a comment.
Kys
A: 

Something is wrong with Date::Manip in the way it localizes special variables. Try to call Date_Init() before you do sorting. It seems to solve the problem:

use strict;
use warnings;

use Data::Dumper;
use Date::Manip qw(UnixDate Date_Init);
my $cars_ref = {
    mazda  => {model => 'mazda', year => '2008' },
    toyota => {model => 'toyota', year => '2001' },
    mitsu  => {model => 'mitsu', year => '2005' }
};

Date_Init(); # Initialize Date::Manip first!

my @models =
  sort {
    UnixDate( $a->{year}, '%o' ) <=> UnixDate( $b->{year}, '%o' );
  } values %$cars_ref;
print Dumper \@models;

Output:

$VAR1 = [
          {
            'model' => 'toyota',
            'year' => '2001'
          },
          {
            'model' => 'mitsu',
            'year' => '2005'
          },
          {
            'model' => 'mazda',
            'year' => '2008'
          }
        ];
zakovyrya
A real question is why anyone would want to map the years above through `UnixDate` to sort.
Sinan Ünür
Besides, omitting the `Date_Init()` call above does not give rise to uninitialized value warnings. On Windows, it pukes because it can't figure out the timezone. Setting `TZ` in the shell fixes that. On Linux, the code above runs fine without the `Date_Init()`. So, your answer does not seem to be related to the OP's problem.
Sinan Ünür
Why wouldn't anyone want to map the years above through UnixDate to sort?
Kys
Actuall zakovyra's solution took away my warnings.
Kys
@Kys There is no need to map years such as `'2001'`, `'2005'` and `'2008'` through `UnixDate` because they will sort just fine using regular `<=>` (or even `cmp`). No one can know what is going on with your code and data because you have not posted a short self contained script that works on a small section of your data. All we have are bits and pieces here and there and this is a consistent theme across your three posts on seemingly the same issue.
Sinan Ünür
@Sinan Ünür I put it merely as an illustration due to lack of actual data, which wasn't available by that time
zakovyrya
@zakovyrya I understand why you did what you did.
Sinan Ünür
@zakovyrya However, note http://search.cpan.org/perldoc/Date::Manip *The above routines all check to make sure that Date_Init is called. If it hasn't been, they will call it automatically. As a result, there is usually no need to call Date_Init explicitly unless you want to change some of the config variables*
Sinan Ünür
@Sinan Ünür: Oh right I was still thinking you were referring to the years as timestamps as I had given in my previous example. But given the data structure I posted, is that sufficient information to work off on? If so, why is it that Date_Init() was able to remove all the warnings? Or is more information required for that?
Kys
@Kys @Sinan Ünür: As I said before it's probably because of the way they localize/do not localize special variables - $a and $b in this case. I noticed that they play well with $_: line local($_)=(); in sub Date_Init().Although it's annoying, it's not that hard to fix it
zakovyrya
@zakovyrya The `$a` and the `$b` in `package Date::Manip` have nothing to do with the `$a` and the `$b` in `package main`.
Sinan Ünür
@Sinan Ünür: Maybe not, don't feel like digging into this right now
zakovyrya
@zakovyrya -1. `$a` and `$b` in the sort block are package global.
Sinan Ünür
+1  A: 

I am going to one last time try to answer this as clearly as possible.

First, if all timestamps are like 2008-08-07T22:31:06Z, there is no need to map them through UnixDate as standard sort using cmp will sort them correctly.

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;
use Date::Manip;

my %args = (
    car_models => {
        a => { year => '2009-08-07T22:31:06Z' },
        b => { year => '2008-08-07T23:31:06Z' },
        c => { year => '2008-08-07T21:31:06Z' },
    },
);

my @sorted_cmp = sort {
    $a->{year} cmp $b->{year}
} values %{ $args{car_models}};

print "Sorted *without* using UnixDate:\n";
print Dumper \@sorted_cmp;

my @sorted_dm = sort {
    UnixDate($a->{year}, '%o') <=> UnixDate($b->{year}, '%o')
} values %{ $args{car_models}};

print "Sorted using UnixDate:\n";
print Dumper \@sorted_dm;

Output (after setting TZ in cmd to placate Date::Manip):

C:\Temp> cars
Sorted *without* using UnixDate:
$VAR1 = [
          {
            'year' => '2008-08-07T21:31:06Z'
          },
          {
            'year' => '2008-08-07T23:31:06Z'
          },
          {
            'year' => '2009-08-07T22:31:06Z'
          }
        ];
Sorted using UnixDate:
$VAR1 = [
          {
            'year' => '2008-08-07T21:31:06Z'
          },
          {
            'year' => '2008-08-07T23:31:06Z'
          },
          {
            'year' => '2009-08-07T22:31:06Z'
          }
        ];

No warnings, no errors ... Ergo, all you have put on this page is one big mess of a red herring. Besides, this still does not explain where the 1249998666 in your other question came from.

Sinan Ünür
H-ha, that's easy one. He put unix timestamps (product of UnixDate) into an array of supposedly hash references of automotive data and later he tried to operate them as if they are hash references:push(@not_sorted_models, UnixDate($_->{'year'},"%o"));hence the error Can't use string ("1249998666") as a HASH ref
zakovyrya
@zakovyrya precisely why I have been asking the OP to show the actual data structures and code he is using and trying to discourage others from going on a wild goose chase with the fragments he has posted in three separate questions so far.
Sinan Ünür
@Sinan Ünür: Sometimes it adds to fun :) Isn't that what this site is all about?
zakovyrya
Thanks for everything. I feel like I just pissed off a few people. The string would be the UnixDate value of a year field in the automotive data.I was thinking UnixDate($_->{'year'},"%o") would return a straight-up integer and not a hash ref, so I thought I was operating with a number.
Kys
Yes YYMMDD form of the date will allow you to sort correctly. I thought an integer comparison would be safest.
Kys
http://www.codinghorror.com/blog/archives/001101.html *Stackoverflow is sort of like the anti-experts-exchange ... with the ultimate intent of collectively increasing the sum total of **good programming knowledge** in the world. ... Better programming is our goal.* Emphasis mine.
Sinan Ünür
@Kys: No, that's exactly what UnixDate returns - straight-up integer,probably what you intended to do is to convert your datastamps into integers, in this case you had to do $_->{year} = UnixDate($_->{year}, '%o');push @not_sorted_models, $_;
zakovyrya
@Kys regardless of what you thought one fact remains: It is not possible to reproduce your problem with the information you posted.
Sinan Ünür
@zakovyrya: Yes, that makes more sense that I would want to insert the whole structure into the array if at the end of my sorting process I wanted to determine the make of the car with the "top" year. Now what if I just wanted to insert the year values (after converting into UnixDate form)@Sinan Ünür: Hopefully the emphasis will be mine one fine day. :)
Kys
http://answers.yahoo.com/question/index?qid=20080630105249AAAUR0o
Sinan Ünür