[Perl5-syntax] signature syntax for method return values

Michael G Schwern schwern at pobox.com
Tue Mar 3 21:02:22 GMT 2009


Florian Ragwitz wrote:
> On Wed, Feb 25, 2009 at 08:00:59PM +0000, Ash Berlin wrote:
>> method to_array (Str $arg) returns ArrayRef[Str] {
>>     return split /,/, $arg;
>> }
> 
> Ok. The majority seems to prefer that. Let's go for it.
> 
> 
> Did you leave of the [] to actually return a array ref on purpose? Do
> you expect the return value to be coerced into the type constraint
> automatically? Even if you didn't: I think we need a way to explicitly
> enable or disable coercion. Any thoughts about the syntax for that?

Coercing return values into references (or vice versa) doesn't buy you much
convenience, very little in Perl 5 coerces references and leads to fun
ambiguities.  For example, what happens with this:

    method foo (Str $arg) returns ArrayRef {
        my @list = something($arg);
        return @list;
    }

If @list is qw(1 2 3) that's easy, it gets coerced into [qw(1 2 3)].  What if
@list is (['foo'])?  What happens there?  It's really an array with the first
element an array ref, but the coercer can't tell the difference without nasty
syntax analysis.  You need to explicitly enable or disable the coercion to
avoid this sort of ambiguity nullifying it's convenience in the first place.
Since you can't predict it, by using reference type coercion you nullify some
of the safety of the return type.  How do you tell what's a mistake and what's
not?

For a real life example, Attribute::Handlers prior to 0.79 tried this sort of
thing. [1]  It interpreted both of these as the same thing:

sub foo :Loud([ 'till', 'ears', 'are', 'bleeding' ]) {...}
sub foo :Loud(  'till', 'ears', 'are', 'bleeding'  ) {...}

Leaving it impossible to pass in an array ref and really confusing as to what
was going on.

This may seem a narrow case, but put it up against what reference type
coercion saves us.  A single backslash?  A single pair of braces?  Unlike
aliasing input arguments, you only need to ref or deref the return value once.
 There is no savings compared to the risk of ambiguity and loss of type
safety.  For example...

   # With coercion
   method foo() returns ArrayRef {
       return map { ... } @stuff;
   }

   # Without coercion
   method foo() returns ArrayRef {
       return [ map { ... } @stuff ];
   }

   # With
   method foo() returns ArrayRef {
       @list = ...;
       return @list;
   }

   # Without
   method foo() returns ArrayRef {
       @list = ...;
       return \@list;
   }

Except that all of the coercion examples actually need "returns ArrayRef has
coercion" or something to avoid ambiguities.

So no, don't coerce references.


[1]  http://www.nntp.perl.org/group/perl.perl5.porters/2007/11/msg130712.html

-- 
191. Our Humvees cannot be assembled into a giant battle-robot.
    -- The 213 Things Skippy Is No Longer Allowed To Do In The U.S. Army
           http://skippyslist.com/list/



More information about the Perl5-syntax mailing list