Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

chromatic (983)

chromatic
  (email not shown publicly)
http://wgz.org/chromatic/

Blog Information [technorati.com] Profile for chr0matic [technorati.com]

Journal of chromatic (983)

Thursday January 13, 2005
02:40 AM

Dark, Dark Corners of Perl

[ #22689 ]

After tonight's PDX.pm meeting, in the bar, I bet Ovid that I could reimplement his Sub::Signatures by replacing the source filter with subroutine attributes. (Wisely, he believed me.)

A few minutes later, he asked idly if I knew of any reason why Perl couldn't call methods with spaces in their names. Offhand, I couldn't think of anything besides the tokenizer that prevents it, believing that gv.c cares more about null-byte termination than the \w+ness of identifiers. If you can bypass that for symbol installation and method invocation (and that's trivial), you've done it.

I hate to give away the punchline before both frightening people who didn't know such things were possible and stumping a few of the people who know it's possible but don't see the answer right away, so here are my tests. They all pass on my machine and I expect them to run just fine on at least Perl 5.8.0 and newer. (Perl 5.6 probably works, but I expect it to fail on more complicated things.) You don't need any non-core modules besides Attribute::Handlers, and I believe that's in the core in the 5.8.x family.

#!/usr/bin/perl -w

BEGIN
{
    chdir 't' if -d 't';
    use lib '../lib', '../blib/lib';
}

use strict;
use Test::More tests => 4;

my $module = 'Attribute::Scary';
use_ok( $module ) or exit;

package Hello;

use strict;
use warnings;

use Attribute::Scary;

sub new
{
    my ($class, $name) = @_;
    bless \$name, $class;
}

sub name :Method
{
    return $$self;
}

sub greet :Method
{
    return sprintf( "Hello, %s!\n", $self->name() );
}

package main;

my $hi = Hello->new( 'Bob' );
is( $hi->greet(), "Hello, Bob!\n",
    ':Method attribute should autoadd invocant shift' );

my $spacey_name  = 'spacey 0';
my $spacey_greet = 'spacey 1';

is( $hi->$spacey_name(), 'Bob',
    '... also installing first method as "spacey 0"' );
is( $hi->$spacey_greet(), "Hello, Bob!\n",
    '... and second as "spacey 1"' );

There are two tricks in the implementation, one of which is an "eww, evil--and CLEVER!" trick and the other is something either you know about or you don't.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • I'm not sure I don't understand the purpose of the excercise, or exactly what the code in Attribute::Scary is supposed to do that the spacey method tests look for, and what's supposed to be unusual about what I see in the tests.

    So I don't know if the teste code is more clever than I am thinking or not.

    Are you referring to the fact that one can install things in the package table that aren't valid identifiers and then get at them using symbolic lookup?

    • Err, “not sure I understand” is, of course, what I meant to say.
    • Well, sometimes exploring the limits of a language is fun, so not everything has to be "practical." And frankly, I think this is fascinating:

      sub greet :Method
      {
          return sprintf( "Hello, %s!\n", $self->name() );
      }

      Let's see, where did that invocant come from? I know he's not using a source filter.

      • I'm not looking for practicality, I'm just wondering exactly which point he's proving.

        As far as the invocant is concerned: PadWalker?

  • I couldn't wrap my head around how to get $self into the subroutine using Attribute::Handlers (I'm assuming that Attribute::Scary uses it). All that I could come up with was this.

    #!/usr/bin/perl
    use strict;
    use warnings;
    use Test::More tests => 3;

    package Hello;
    use strict;
    use warnings;

    sub new {
        my ($class, $name) = @_;
        bless \$name, $class;
    }

    sub name {
      my $self = shift;
      return $$self;
    }

    sub greet {
      my $self = shift;
      return sprintf( "Hello, %s!\n", $self-

  • When do we get to see Attribute::Scary?