GSP
Quick Navigator

Search Site

Unix VPS
A - Starter
B - Basic
C - Preferred
D - Commercial
MPS - Dedicated
Previous VPSs
* Sign Up! *

Support
Contact Us
Online Help
Handbooks
Domain Status
Man Pages

FAQ
Virtual Servers
Pricing
Billing
Technical

Network
Facilities
Connectivity
Topology Map

Miscellaneous
Server Agreement
Year 2038
Credits
 

USA Flag

 

 

Man Pages
Sub::Signatures(3) User Contributed Perl Documentation Sub::Signatures(3)

Sub::Signatures - Use proper signatures for subroutines, including dispatching.

  use Sub::Signatures;
  
  sub foo($bar) {
    print "$bar\n";
  }

  sub foo($bar, $baz) {
    print "$bar, $baz\n";
  }

  foo(1);     # prints 1
  foo(2,3);   # prints 2, 3
  foo(2,3,4); # fatal error

  sub bar($var) {
    print "$var\n";
  }

  sub bar(fallback) {
    my ($this, $that) = @_;
    print "fallback $this, $that\n";
  }
  
  bar(1);   # prints 1
  bar(2,3); # prints fallback 2, 3
  bar(2,3);

 Signature based method overloading in Perl.

WARNING: Not backwards-compatible to Sub::Signatures 0.11.

One of the strongest complaints about Perl is its poor argument handling. Simply passing everything in the @_ array is a serious limitation. This module aims to rectify that.

With this module, we an specify subroutine signatures and automatically dispatch on the number of arguments.

We often see things like this in Perl code:

 sub name {
   my $self = shift;
   $self->set_name(@_) if @_;
   return $self->{name};
 }

 sub set_name {
   my $self = shift;
   $self->{name} = shift;
   return $self;
 }

The intent here is to allow someone to do this:

  my $name = $person->name; # fetch the name
  $person->name('Ovid');    # set the name

Most modern programming languages have multi-method dispatching. The intent of "Sub::Signatures" is to fix this problem painlessly by allowing signature based method dispatch.

Here's how it works:

  use Sub::Signatures qw/methods/;

  # ...

  sub name ($self) {
    return $self->{name};
  }

  sub name ($self, $name) { 
    $self->{name} = $name;
  }

Later:

  print $object->name;  # prints current name
  $object->name($name); # sets current name
  $object->name(qw/Publius Ovidius/); # fatal runtime error

NOTE: all arguments in signatures must be scalars. Perl does not handle flattening of hashes or arrays very gracefully.

For a group of subroutines or methods with the same name but different arguments, calling this subroutine with a different number of arguments from those available in any signature will cause a fatal runtime error. If this is too restrictive, use a 'fallback' subroutine or method.

  sub name ($self) {
    return $self->{name};
  }

  sub name ($self, $name) { 
    $self->{name} = $name;
  }

  sub name(fallback) {
    my ($self, @args) = @_;
    $self->{name} = join ' ', @args;
  }

Later:

  print $object->name;  # prints current name
  $object->name($name); # sets current name
  $object->name(qw/Publius Ovidius/); # sets name to 'Publius Ovidius'

Note that forcing the programmer to explicitly label a subroutine as a 'fallback' ensures that even if that subroutine is not located near any of the others with the same name, it's still clear to a maintenance programmer that the subroutine may be overloaded.

The default behavior of "Sub::Signatures" is to assume that signatures are on subroutines. If you use this with OO programming and have methods instead of functions, you must specify "methods" mode. This is because we have to be able to dispatch to a parent class if the method isn't found in the current class.

 package ClassA;
 
 use Sub::Signatures qw/methods/;
 
 sub new($package, $properties) { 
    bless $properties => $package;
 }
 
 sub foo($class, $bar) {
     return sprintf "arrayref with %d elements" => scalar @$bar;
 }
 
 sub name($self) {
     return $self->{name};
 }

 sub name($self, $name) {
     $self->{name} = $name;
     return $self;
 }
 
 1;

While multi-dispatch doesn't make much sense in the context of anonymous subroutines, we can still use subroutine signatures with them:

 sub foo($bar) {
   return sub ($this) { "$this $bar" }
 }

Also, though there is special handling for "methods", anonymous subroutines can be safely mixed with methods.

Currently supported features:
  • Methods

     use Sub::Signatures 'methods';
        

    Note that if you use 'methods', you cannot use signatures with subroutines which are called in a non-Object-Oriented fashion.

     use Sub::Signatures 'methods';
    
     sub _reverse_text { # must not have signature
       my $text = shift;
       return scalar reverse $text;
     }
    
     sub new ($class) {
        bless {}, $class;
     }
    
     sub new ($class, $data) {
        die "Argument to new() must be a hashref'
          unless ref $data eq 'HASH';
        bless $data, $class;
     }
     
     sub name ($self) {
        return $self->{name};
     }
    
     sub name ($self, $name) {
        $self->{name} = $name;
     }
        
  • Subroutines

     use Sub::Signatures;
    
     sub foo ($data) {
       ...
     }
    
     sub foo ($arg1, $arg2) {
       ...
     }
        
  • Exporting

     use base 'Exporter';
     use Sub::Signatures;
     our @EXPORT_OK = qw/foo/;
    
     sub foo($bar) {...}
    
     sub foo($bar, $baz) {
         ...
     }
        
  • No duplicate signatures

     use Sub::Signatures;
     sub foo($bar) {}
     sub foo($baz) {} # won't compile
        
  • Inheritance

     use Sub::Signatures 'methods';
        

    Specifying "methods" allows "Sub::Signatures" to call your method correctly rather than call it as a subroutine.

  • Anonymous subroutines

     my $thingy = sub ($foo, $bar) { ... };
        

    Unlike named subs, the number of arguments is not checked, so this is equivalent to:

     my $thingy = sub { my ($foo, $bar) = @_; ... };
        
  • Useful error messages

    The error messages bear some explaining. If your code cannot find the correct method to dispatch to, you'll see something like this:

     Could not find a sub matching your signature: foo(SCALAR, SCALAR) at ...
        

    Or:

     Could not find a method matching your signature: foo(SCALAR) at ...
        

    If used in method mode, the first argument to a method is actually a class or instance of a class, but this is not in the argument list in the error message because this seems counter-intuitive:

     $object->foo($bar);
        

    It looks like there's really only one argument (even though we know better) and for various reasons, the code is a bit cleaner when the error message is handled this way.

The first version of this alpha allowed optional strong typing by letting you specify the exact ref type each argument should be:

 sub foo (ARRAY $bar, HASH $baz, CGI $query) {
   ...
 }

Why did this go away? There were several problems. First, specifying the exact data type meant that isa relationships were ignored. However, if we were to check isa relationships, this sometimes leads to problems with ambiguous method resolution.

The real nail in the coffin was that "CGI $query" parameter above. What if we actually have a "CGI::Simple" object passed in instead? It almost completely conforms to the "CGI" interface. If it does what we want, the type checking guarantees that that this method will fail for no good reason.

However, no argument checking is a bad thing. What we're really interested in is whether or not a given argument is capable of providing what we need, not whether or not it's a given type. This puts your author in a bind. Objects which are unrelated by inheritance but present the same behaviors are known as allomorphic.

Allomorphism, despite the funny name, is something Perl programmers use all the time without being aware of what it's called. However, to add allomorphism support to this module would complicate it quite a bit. Thus, to keep things as simple as possible, we restrict ourselves to dispatching on the number of arguments. Thus, you, the programmer, will still need to validate the different types and/or capabilities of the arguments you pass in.

If you prefer, you can still list the data type before the argument:

  sub foo (ARRAY $bar) {...}

However, the "ARRAY" will be discarded. Think of it as documentation.

For the most part this module just works. If you are having problems, consult this list to see if it's covered here.
  • "sub foo {}"

    Due to limitations with parsing Perl, this module does not attempt to take advantage of "Filter::Simple"'s "FILTER_ONLY" functionality. This means that this module is a straightforward filter. As a result, if you have text in quoted areas which resembles "signified" subroutines, you may see strange results. Fortunately, this is very rare.

  • Do not mix "signatured" subs with "non-signatured" of the same name

    In other words, don't do this:

     sub foo($bar) { ... }
     sub foo { ... }
        

    If you want something like that, name a Fallback subroutine:

     sub foo($bar) { ... }
     sub foo(fallback) { ... }
        

    However, you don't need signatures on all subs. This is OK:

     sub foo($bar) { ... }
     sub baz { ... }
        
  • Use caution when mixing functions and methods

    Internally, functions and methods are handled quite differently. If you use this with a class, you probably do not want to use signatures with functions in said class. Things will usually work, but not always. Error messages will be misleading.

      package Foo;
      use Sub::Signatures qw/methods/;
    
      sub new($class) { bless {} => $class }
    
      sub _some_func($bar) { return scalar reverse $bar }
    
      sub some_method($self, $bar) { 
          $self->{bar} = _some_func($bar);
      }
    
      sub some_other_method($self, $bar, $baz) {
          # this fails with 
          # Could not find a method matching your signature: _some_func(SCALAR) at ...
          $self->{bar} = _some_func($bar, $baz);
      }
    
      1;
        
  • One package per file.

    Currently we cannot handle more than one package per file with this module. It sometimes works with methods, but there are no guarantees. When we can parse Perl reliably, this may change :)

  • Can only handle scalars and references in the arg list.

    At the present time, the only variables allowed in signatures are those that begin with a dollar sign:

     sub foo($bar, $baz) {...}; # good
     sub foo($bar, @baz) {...}; # not good
        
  • Handle prototypes correctly

    Don't try using prototypes with this module. It currently tends to get caught in an infinite loop if you do that, so don't do that.

     use Sub::Signatures;
    
     sub foo($$) {...} # don't do that
        

    See "t/90prototypes.t" and the code at the end if you want to fix this.

    Of course, prototypes in Perl are widely considered to be broken anyway, so why use them?

In a nutshell, each subroutine is renamed with a unique, signature-based name and a sub with its original name figures out how to dispatch to it. It loosely works like this:

 package Some::Package;

 sub foo($bar) {
     return [$bar];
 }
 
 sub foo($bar, $baz) {
     return exists $baz->{$bar};
 }

In loose mode, this becomes:

 # note that only the number of arguments is checked

 package Some::Package;

 sub foo {
     goto &__foo_1 if 1 == @_;
     goto &__foo_2 if 2 == @_;
     # die with a useful error message unless we have a fallback subroutine
 }

 sub __foo_1 { my ($bar) = @_;
     return [$bar];
 }

 sub __foo_2 { my ($bar, $baz) = @_;
     return exists $baz->{$bar};
 }

There's a bit more magic involved when it comes to methods, particulary with trying to call an inherited method if one is not found in the current package. However, this should give you a rough idea of what's going on and also give you fair warning that deliberately naming subs things like "_subname_$digit" is a bad thing.

None.

This is beta code. Many people understandably do not wish to use beta code in production. To get this code robust enough for production use, send me bug reports. Send me patches. Send me requests. Send me feedback.

Naturally, since this is beta code, the interface is probably stable. I have no intention of changing it unless I need to. Hopefully I've not made any boneheaded mistakes that necessitate this, but I will not guarantee that I am not, in fact, boneheaded.

However, if you use this module, please let me know. If things do change, I'd like to give folks a heads up.

Filter::Simple

Yes, this is based on a source filter. If you can't stand that, don't use this module. However, before you ignore it, read <http://use.perl.org/~Ovid/journal/22152>.

Attribute::Signature

Perl6::Subs

Perl6::Parameters

Curtis "Ovid" Poe, <moc tod oohay ta eop_divo_sitruc>

Reverse the name to email me.

Copyright 2004-2005 by Curtis "Ovid" Poe

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

2005-12-03 perl v5.32.1

Search for    or go to Top of page |  Section 3 |  Main Index

Powered by GSP Visit the GSP FreeBSD Man Page Interface.
Output converted with ManDoc.