flowdy has asked for the wisdom of the Perl Monks concerning the following question:
Dear Monks,
Following up an earlier PM post of mine, which is Re^6: A Melancholy Monkday, and also another question in 2005, What's most efficient way to get list context?, I would still like to advocate a list() operator. I encountered edge cases where it can come in handy, would reduce hours debugging and working around the Newbies' nightmares, the dim parts in the Perl language design. I have to admit that these edge cases I pondered on have some esotheric smell, but anyway here you are:
In your opinion, is it worth a feature request?
=begin perldoc -f list
The list() operator enforces list context on its arguments. It returns always a flat list of all scalars contained in passed arrays or hashes or the values returned by subroutine calls. It enforces list context for them even where e.g. return "inherits" the scalar context from the environment of the subroutine call. It guarantees that the values are rvalues and not aliased beneath.
Example:- sub { return grep { ... } $your, @values, $here } returns either all grepped values or the number of them, depending on context (cf. documentation of grep). This is probably not what the users of your module want.
- sub { return list grep { ... } $your, @values } returns in scalar context the last item of @values, so it behaves like a sub that returns a literal comma-separated list of scalars.
Test code:
#!/usr/bin/perl use strict; use Test::More; # Pure perl mock-up of builtin list() counterpart to scalar() sub list { return @_[ 0 .. $#_ ]; } # Our example demo function, it doesn't do anything useful however # ---------------------------------------------------------------- sub incr_str_returned_from { my $sub_ref = shift; # You might be a careful professional and pick one explicitly: # my $scalar = ( $sub_ref->() )[-1]; # But you might be not and forget to make sure a given # sub-ref returns something useful in scalar context. You might # consider it to return a list and conclude that you'll simply # increment the last value in it. But this is not safe: my $scalar = $sub_ref->(); return ++$scalar; # (Did you know: Perl increments alphabetic # strings like numbers of base 26) } my @expected = qw( xxx foo bar baz ); is_deeply [ Client::Module::valid_scalars_1() ], \@expected, "test without list() in list context"; is_deeply [ Client::Module::valid_scalars_2() ], \@expected, "test with list() in list context"; is incr_str_returned_from(\&Client::Module::valid_scalars_1) => 5, "Oops, grep without list() maybe 'misbehaves' in scalar context:" ." gets number of elements"; is incr_str_returned_from(\&Client::Module::valid_scalars_2)=>'bba', "list(grep ...) in scalar context:" ." evaluates to last value like literal lists"; my %hash = ( a => 3 ); my @test1 = \( $hash{a}, @expected, 'zzz' ); is scalar grep( { ref eq 'SCALAR' } @test1 ), 2, "Without list(), we get a list of references to lvalues"; my @test2 = \( $hash{a}, list(@expected), 'zzz' ); is scalar grep( { ref eq 'SCALAR' } @test2 ), 6, "With list(), we get a list of references to plain rvalues"; ${ $test2[0] }++; is $hash{a}, 4, "Indirect increment via reference to hash element"; ${$test2[2]} = 'bla'; TODO: { local $TODO = "Perl core devs be welcome to decide if they " . "implement list() that way or not"; is $expected[1], 'bla', "Values returned by and passed to list() are identical"; } done_testing; package Client::Module; sub valid_scalars_1 { return grep { defined $_ } # stub grep routine 'xxx', qw(foo bar baz), undef; # demo values } sub valid_scalars_2 { return ::list valid_scalars_1() } __END__
Any comments appreciated oh wise,
-- flowdy
|
---|