The gmtime function normally returns a list, and you have to remember what's in what position. However, you can use the Time::gmtime module which makes it return a hash reference instead.

In Perl 6, the function can detect more contexts, and do this built-in. But what about today?

My idea is to return a pseudo-hash. For example, here is a function that returns a bunch of values:

sub FileTimeToSystemTime ($) { my $input= shift; # binary data formatted as an int64 my $output= '.' x 16; # 16 byte structure output. my $result= $f->Call ($input, $output); # ... check $result for errors. my @retval= unpack ("v*", $output); # Year, Month, DayOfWeek, Day +, Hour, Minute, Second, Milliseconds unless (wantarray) { # ... format this into a ctime-like string return $string; } ### here is the interesting part: unshift @retval, \@names; return @retval; }
Now, there is an extra value at the beginning of the array. But that doesn't really change the fact that you need to remember what's in what position—only the actual positions are affected, not the logic or the issue.
my ($names, $Year, $Month, $DayOfWeek, $Day, $Hour, $Minute, $Seco +nd, $Milliseconds)= FileTimeToSystemTime ($int64);
I can ignore the $names variable, or if I'm only interested in the Day, could subscript the array with [4] (not 3).

However, without using a separate form of the function, I could do this:

my $value= \(FileTimeToSystemTime ($int64)); my $Day= $value->{Day}; # ... etc.
That is, I can invoke the power of the pseudo-hash, or ignore it and use the list.

What do y'all think of this idea?

Meanwhile... what's the story of pseudo-hashes in general? I think I saw in the Apocolipse that they are going away in Perl 6 and Larry calls them a failed experiment. What's he got against them? Is some other feature going to take its place (In Perl 6 this function would look for hash context, so it won't need the pseudo-hash).

—John

Replies are listed 'Best First'.
Re: Returning A Pseudo-Hash in Array Context
by LD2 (Curate) on Jul 10, 2001 at 05:58 UTC
    You may want to read this: Pseudo-Hashes Must Die!. It's a bit of history and explanation about pseudo-hashes and why they will most likely not be used in Perl 6.
Re: Returning A Pseudo-Hash in Array Context
by frag (Hermit) on Jul 10, 2001 at 19:23 UTC
    First: "unshift @retval, \@names;" only works if @names = ( a => '1', b => '2', etc);

    Second: "That is, I can invoke the power of the pseudo-hash, or ignore it and use the list."
    True, if you remember to throw out the first value when you're just using it as a list. Can you be sure that you or whoever inherits this code will always do that?

    Third: If I've got this right, one of the key things about psuedohashes is that unless you create them as a typed lexical variable (e.g. 'my MyGMTime $time;') AND have a 'use fields qw(all my fields in proper order)' in your package, then the pseudohash conversion (taking what looks like hashrefs but converting them into arrayrefs) will be done at run time, not compile time. The result still gives you the easier, hash-style interface, but it's slower than either a straight array or a hash. Doing it at compile time is nice, but you have to jump through these hoops.

    My advice: If you only want mnemonic accessors while maintaining an array structure, return a blessed array and create a generic "get" accessor that maps strings to positions. Here's what it would look like:

    package MyGMTime; # MUST be ordered correctly: use enum qw(sec min hour mday mon year wday yday); sub new { my ($class) = shift; my @values = gmtime(); bless [@values], $class; } sub get { my ($self, $field) = @_; no strict 'refs'; return $self->[&$field]; } package main; my $x = MyGMTime->new; print $x->get("year"), "\n"; # mnemonic/hashly print $$x[5], "\n"; # arrayish
    Or, if you don't want to use enum.pm:
    ### use this instead of the 'use enum' statement: my %index = ( sec => 0, min => 1, hour => 2, mday => 3, mon => 4, year => 5, wday => 6, yday => 7, ); ### Replace get() with this. All remaining code is identical. sub get { my ($self, $field) = @_; return $self->[$index{$field}]; }

    -- Frag.

(tye)Re: Returning A Pseudo-Hash in Array Context
by tye (Sage) on Jul 10, 2001 at 23:34 UTC

    Thankfully, LD2 already addressed why pseudo hashes suck. One solution I've used for cases like this is to support multiple types of requests:

    my( $day, $month, $year )= FileTimeToSystemTime( $int64, qw(day month year) ); my @date= FileTimeToSystemTime( $int64 ); FileTimeToSystemTime( $int64, \(my %date) );

            - tye (but my friends call me "Tye")
      So, the caller specifies the order, rather than remembering it. I like. Thanks, that's more food for thought.

      —John