Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer

A vexing list vs. scalar context question.

by theguvnor (Chaplain)
on Jan 31, 2002 at 23:47 UTC ( #142547=perlquestion: print w/replies, xml ) Need Help??

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

In my latest folly, I changed an object to use several accessor methods that would return a scalar, rather than one accessor that would return a hash ref (that had to be dereferenced and I figured was an extra hassle for any script using the module).

So, rather than getting a value like my $dir = $site->dirs()->{'uploads'};, I could write my $dir = $site->upload_dir;

All well and good, except my object also has a couple of accessor methods that should return arrays rather than scalars, so my return from the accessor method looks like:

return @{$self->{$slot}} if wantarray; return $self->{$slot};

It must be noted I'm using closures in a loop to create the accessor methods, hence the conditional return. See my accessor generator at the bottom.

End of preamble - this is where I got tripped up and nearly went insane - in my calling script, I wanted to join the return from the 'upload_dir' method to something else, like so:

my $dir = join '/', $site->upload_dir, $user->id;

Now, it should be obvious given my preamble that because I have called the upload_dir method in list context (because join expects a list) my method will return (or try to return) a "listified" version of my scalar upload_dir value, and hence won't be what I'm looking for - in this case, it ended up returning an empty list, and messing everything up.But it took me over an hour to figure this out (I'm not too bright at times :).

What I can't figure out is why use strict; and use warnings; didn't throw me some kind of message about trying to turn my scalar (upload_dir) into an array to return from the method?

####################################################### # generate the generic accessor methods using closures: for my $property (keys %properties) { my $slot = __PACKAGE__ . "::$property"; no strict 'refs'; # so symbolic ref to typeglob works - see The + Camel p.338 *$property = sub { my $self = shift; if (@_) { if ( ref $_[0] ) { # arg is a ref, just store it $self->{$slot} = shift; } elsif ( $properties{$property} eq 'ARRAY' ) { # transla +te array to arrayref $self->{$slot} = [@_]; } elsif ( $properties{$property} eq 'HASH' ) { # translat +e hash to hashref $self->{$slot} = {@_}; } elsif ( $properties{$property} eq 'SCALAR' ) { # scalar +, no translation $self->{$slot} = shift; } else { die "Problem with $slot"; } } return @{ $self->{$slot} } if wantarray; return $self->{$slot}; }; }

Replies are listed 'Best First'.
Re: A vexing list vs. scalar context question.
by japhy (Canon) on Feb 01, 2002 at 00:21 UTC
    To answer your bolded question, it's because you explicitly turned off strict references! And you might need to rethink your wantarray return value, since @{ $self->{foo} } won't dereference a hash reference...

    Jeff[japhy]Pinyan: Perl, regex, and perl hacker.
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

      Shoot.. right there in front of me... thanks japhy. Here's my return volley though - so how would one go about returning a hash (by dereferencing a hashref) if one is called for - there is no wanthash function! Or do I simply test for wantarray still, but do my lookup for what type of variable should be stored in that slot from my %properties hash?

      Any hints appreciated.

        wantarray is a misnomer -- it should be wantlist. And my response is:
        if (wantarray) { # handle scalars too! return $self->{$x} if not ref $self->{$x}; # handle arrays return @{ $self->{$x} } if ref $self->{$x} eq 'ARRAY'; # handle hashes return %{ $self->{$x} } if ref $self->{$x} eq 'HASH'; # panic! die "unknown reference type (", ref($self->{$x}), ")"; } else { return $self->{$x} }

        Jeff[japhy]Pinyan: Perl, regex, and perl hacker.
        s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://142547]
Approved by root
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (4)
As of 2021-12-06 23:38 GMT
Find Nodes?
    Voting Booth?
    R or B?

    Results (33 votes). Check out past polls.