[% setvar title Improved parsing and flexibility of indirect object syntax %]
To see what is currently happening visit http://www.perl6.org/
Improved parsing and flexibility of indirect object syntax
Maintainer: Nathan Wiger <nate@wiger.org> Date: 29 Aug 2000 Last Modified: 29 Sep 2000 Mailing List: perl6-language-objects@perl.org Number: 174 Version: 3 Status: Frozen
Currently, Perl 5 makes a distinction between routines called in the indirect object vs. function form:
$r = new CGI; # CGI->new $r = new CGI (@args); # CGI->new(@args) $r = new(CGI @args); # mail::new(main::CGI(@args))
This causes many problems, such as having to have special prototypes that translate the optional first argument object into the indirect object syntax. Special cases like this, and the inability to prototype
print(HANDLE @list);
Have led some to suggest indirect objects be expunged altogether.
However, inflexbility is not the solution to this problem, since there are many benefits to indirect object syntax. In Perl 6, the distinction between function and indirect object syntax should be dropped. Instead, the second form should be automatically translated to the first when possible. This increased flexibility allows prototyping of key functions while still being able to take advantage of indirect objects.
Currently, indirect objects can only be a scalar, block, or bareword. This RFC proposes that this concept be extended to any valid singular thingy. So in Perl 6 these:
print $handles{'mainout'} "Hello, world!";
print $output[0] "Hi there!";
Should work as indirect objects. Code references should still have to be enclosed in blocks, since this is needed to reduce ambiguity between indirect objects and chained functions.
Let's get into a more common example:
print @data; print(@data); print STDERR @data; print(STDERR @data);
Currently, the fact that all of these can coexist contributes to the fact that CORE::print is not prototypeable/overrideable, which is a bad thing, obviously. That last one is particularly sticky, since it would intrinsically be parsed as something like:
CORE::print(main::STDERR(@data));
But now we have to have special rules to deal with this. I'm going to digress for a moment and skip barewords, coming back to them later.
Assuming that the above became scalar filehandles:
print $STDERR @data; print($STDERR @data);
We can add a simple parsing rule to convert the second form into the first:
If the first argument to a function is a scalar value which is not followed by a comma, then that value is the indirect object for that function.
So, under this rule, the above two would both become:
$STDERR->print(@data);
Assuming that print really did work as a true indirect object. This rule generalizes to any function:
clone($obj @args); # $obj->clone(@args) mogrify($trans[0] @stuff); # $trans[0]->mogrify(@stuff);
So, this allows us to use the current print(HANDLE @data) form
without special parsing rules. Notice that this rule does not allow
you to do this:
do_stuff(@data);
and expect Perl to magically figure out that $data[0] is an object
reference. That's just too weird. The first argument must be a
scalar without a trailing comma.
At first, this may seem like syntactic sugar. It's not, it's much more than that.
In fact, this makes Perl 6 much more flexible and reduces the number of
core methods, without confusing the end user with inconsistent syntax.
In fact, methods such as close and open could leave core
altogether, instead being called on the objects:
$FILE = open(http "www.yahoo.com"); # http->open close($FILE); # $FILE->close
It should be obvious what the benefits of being able to do this are.
It makes the core syntax much more flexible, and reduces the need to include simple translator prototypes. This makes RFC 168: Built-in functions should be functions, much more realistic since these prototypes no longer have to handle the special case of an "optional first argument object". For example:
print($STDOUT @data) becomes $STDOUT->print(@data);
automatically via parsing, meaning that CORE::print can be a prototypeable function.
The following ambiguity exists in Perl 5 which is neither solved nor made worse by this RFC. However, it is worth addressing since we're talking about indirect objects.
When the indirect object is a bareword, considerable ambiguity exists which can actually be quite difficult to resolve cleanly:
$p = new Person name => $name, age => $age;
The above example is valid in Perl 5. However, it can be difficult to read and maintain, and many people would promote disambiguating it in one of the following ways:
$p = new Person (name => $name, age => $age);
$p = new {Person} name => $name, age => $age;
$p = Person->new(name => $name, age => $age);
Under this RFC, you would be able to write this as well:
$p = new(Person name => $name, age => $age);
However, note that like the first disambiguating case above, you are
still stricken with the problem that if the person defines
main::Person, that will be called, and not your indirect object,
resulting in parsing as such:
$p = main::new(main::Person(name => $name, age => $age));
RFC 244 suggests that the bareword indirect object be dropped altogether to resolve this ambiguity. While I do find this disturbing in a way, it is hardly the only syntactic ambiguity in Perl and bareword indirect objects are, in most cases, is quite useful.
Because this RFC neither helps nor hurts this specific ambiguity, it defers to whatever is decided with barewords and simply states: The precedence rules for bareword indirect objects inside parens should be the same as for those outside parens.
Add the singular rule:
If the first argument to a function is a scalar value which is not followed by a comma, then that value is the indirect object for that function.
To Perl's parsing. Changes to toke.c (or the equivalent in Perl 6)
would be required.
This introduces new functionality that does not break any existing code. No translation should be required.
RFC 14: Modify open() to support FileObjects and Extensibility
RFC 168: Built-in functions should be functions
RFC 244: Method calls should not suffer from the action on a distance