[% setvar title Improved parsing and flexibility of indirect object syntax %]

This file is part of the Perl 6 Archive

Note: these documents may be out of date. Do not use as reference!

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.


Indirect objects should be any valid single value

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.

Indirect objects should be enclosable in parens

Let's get into a more common example:

   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:


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:


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:


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.

Why this is a needed

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.

Ambiguity: Bareword indirect object

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