V
Veli-Pekka Tätilä
Hi,
I think I've noticed a discrepancy about user and built-in functions taking
code refs. Where as, say, List::Util::reduce (prototyped &@) let's one pass
a code ref, map and grep enable one to also pass an expression as the first
argument. So:
both:
map { lc } @list;
and
map lc, @list;
Do the same thing. Conceptually, the expression is passed as a whole and
evaluated lazily later on as though it was a sub-routine, I suppose.
But in this snippet dealing with a user function, trying to use an
expression terminated by a comma throws a syntax error:
reduce { $a * $b } @list;
reduce $a * $b, @list; # Won't compile.
That is:
Type of arg 1 to List::Util::reduce must be block or sub {} (not
multiplication (*))
Apparently the built-ins don't parse quite the same way as the
user-functions prototyped with the & character. This notion is backed up by
the prototype function. Asking it for the map prototype just hands me undef
unless I've typoed:
print prototype 'CORE::map';
Not being able to prototype reduce and my own list functions as
func EXPR, LIST
is only slightly annoying. However, I'd like to ask why this difference
exists. That is, why not interpret the first argument & like map and grep do
it, when it isn't a code ref? From the user functions point of view it
could be indistinguishable from a normal code ref.
The only downside I can see is not being able to use something totally
different from a code ref as the first argument, of a user sub then. I'm not
sure how common that is, though. Maybe Perl could do a heuristic guess as
to whether you ment an expression to be evaluated as a coderef (operands and
operators) or wanted to pass around a simple variable in a user function. A
safer way would be reserving a different prototype character for the
map-like behavior, I suppose. These are just some vague suggestions that
occurred to me as I don't know all that much about Perl parsing.
Speaking of functions in which the next comma in the list has "special
significance", unary list operators come to mind:
print lc 'FOO', 'bar';
lc's argument list is ended by the first comma in prints arguments. Kind of
like, by association, how the first comma in map separates its expression
and list parts.
I suppose working exactly like map or grep might cause additional problems
with some other Perl constructs I have not thought of. Nevertheless, it
would be the expected behavior for me, or maybe I've got unusual
expectations, <grin>. At any rate, I've got a feeling I've overlooked
something essential which would prevent the func EXPR, LIST construct from
working well for user functions. Wonder what that might be or have I
answered my own question already? That is too much ambiguity, the
possibility of breaking old code and serious limitations on the polymorphism
of sub-routine arguments. And all this for a mere minor inconvenience that's
easily fixed by using braces.
I think I've noticed a discrepancy about user and built-in functions taking
code refs. Where as, say, List::Util::reduce (prototyped &@) let's one pass
a code ref, map and grep enable one to also pass an expression as the first
argument. So:
both:
map { lc } @list;
and
map lc, @list;
Do the same thing. Conceptually, the expression is passed as a whole and
evaluated lazily later on as though it was a sub-routine, I suppose.
But in this snippet dealing with a user function, trying to use an
expression terminated by a comma throws a syntax error:
reduce { $a * $b } @list;
reduce $a * $b, @list; # Won't compile.
That is:
Type of arg 1 to List::Util::reduce must be block or sub {} (not
multiplication (*))
Apparently the built-ins don't parse quite the same way as the
user-functions prototyped with the & character. This notion is backed up by
the prototype function. Asking it for the map prototype just hands me undef
unless I've typoed:
print prototype 'CORE::map';
Not being able to prototype reduce and my own list functions as
func EXPR, LIST
is only slightly annoying. However, I'd like to ask why this difference
exists. That is, why not interpret the first argument & like map and grep do
it, when it isn't a code ref? From the user functions point of view it
could be indistinguishable from a normal code ref.
The only downside I can see is not being able to use something totally
different from a code ref as the first argument, of a user sub then. I'm not
sure how common that is, though. Maybe Perl could do a heuristic guess as
to whether you ment an expression to be evaluated as a coderef (operands and
operators) or wanted to pass around a simple variable in a user function. A
safer way would be reserving a different prototype character for the
map-like behavior, I suppose. These are just some vague suggestions that
occurred to me as I don't know all that much about Perl parsing.
Speaking of functions in which the next comma in the list has "special
significance", unary list operators come to mind:
print lc 'FOO', 'bar';
lc's argument list is ended by the first comma in prints arguments. Kind of
like, by association, how the first comma in map separates its expression
and list parts.
I suppose working exactly like map or grep might cause additional problems
with some other Perl constructs I have not thought of. Nevertheless, it
would be the expected behavior for me, or maybe I've got unusual
expectations, <grin>. At any rate, I've got a feeling I've overlooked
something essential which would prevent the func EXPR, LIST construct from
working well for user functions. Wonder what that might be or have I
answered my own question already? That is too much ambiguity, the
possibility of breaking old code and serious limitations on the polymorphism
of sub-routine arguments. And all this for a mere minor inconvenience that's
easily fixed by using braces.