On Sat, 24 Apr 2004, John Siracusa wrote:

> Based on the "default accessors and encapsulation" thread, it seems like a
> Perl 6 equivalent of Class::MethodMaker will be still be useful in our (or
> at least "my") Brave New World.  I've been pondering the best way to create
> such a beast in Perl 6.

Yes, I agree. As you point out below, Class::Makemethods does lots of
crazy stuff. Much of that (like pre- and post-hooks) will be easier to
write in P6, but there is still lots of stuff that won't be in the core.

>
> The most common two Perl 5 techniques are:
>
> 1. Use a string eval: build up a big string that looks the code for the
> method that I would have typed myself if I wasn't so lazy, then eval the
> string and assign the resulting code ref to the appropriate typeglob.
> Example:
>
>     $attr = 'baz';
>     *{"Foo::$attr"} = eval qq(sub { \$_[0]->{'$attr'} });


> This technique seems to have the best runtime performance in Perl 5 (by a
> small margin), but it's also much more expensive (not to mention tedious and
> persnickety) to create the method in the first place.  For whatever reason,
> it's always just struck me as "wrong" (sort of like source filtering where
> code is just seen as a giant string--something that Perl 6 blessedly saves
> us from :)
>
> 2. Use a closure: build a method by assigning what would normally be
> constant values to a set of variables, then capturing their state in a
> closure.  Example:
>
>     $attr = 'baz';
>     *{"Foo::$attr"} = sub { $_[0]->{$attr} };

Symbol tables and typeglobs and such belong to A10... and the * has been
stolen... so I'll just speculate in pseudocode.
Blocks-are-subroutines makes life easier, and in pseudocode that can be
just:
  *{"Foo::name1"} = -> $a { $a->{name1} };
OR:
  for @names -> $name {
        my $private_scalar = $name;
       *{"Foo::$name"} = -> $a {$a->{$private_scalar}};
  }



>
> Making the method this way has always seemed "cleaner" to me, but it bothers
> me that $attr a full blown variable that has to be read from every time the
> method is run.

> Really, it should be a constant, which is probably why the
> string eval version has a speed edge at runtime.

That is something the compiler may be able to deal with. I don't know much
about compilers, but here is something from the camel book, 3rd ed, page
229 about inlining functions:

BEGIN {
        my $prod = 1;
        for (1..10) { $prod *= $_; }
        sub NFACT () { $prod }
}

Here, NFACT is inlined because the compiler sees that $prod can never
change. So maybe the $private_scalar above can also be inlined. (There is
a new $private_scalar each time through the loop because of the my, and
$name is also implicitly my).  For that code I did not need to introduce
$private_scalar, but I put it there to stand for more complex calculations
if you need there.

 Maybe there should be a way to give hints to the compiler that inlining
maybe possible.

> The two Perl 5 techniques still seem like they will work (albeit with
> different syntax), but I'm sure there are better ways...perhaps something
> involving macros?  The ideal solution has the strengths of both Perl 5
> techniques, but none of their weaknesses.  Creation should be fast and
> clean, and there should be no wasted overhead when calling the generated
> methods.  It should be just as if I wrote the methods myself.

>
> I haven't retained enough Perl 6 syntax to have any idea what this would
> look like, so I'm looking for suggestions.  Which Perl 6 features are best
> suited to creating a good Perl 6 MethodMaker?  Anyone want to post some
> simple examples?

Wicked Traits come to mind. They seem to be all about warping class
behaviors...

role methodmaker{
  method trait_auxillary:install( : Class $container, $method_semantics,
                                        [EMAIL PROTECTED]){
        given $method_semantics {
           when "semantics1" {
                for @names -> $name {
                    ...
                    my $method = -> $arg {...};
                    $container.install($name, $method);
                }
                for @names -> $name {
                   my $method = $container.get_method($name);
                   $method.i_wont_change___inline_variables_if_possible;
                }
           }
        }
  }
}

# And in our class:
class Dog{
        install "some_semantics", <<bark howl whine>>;
}

Or perhaps you want to put the install in a BEGIN{} if you want to have
the body of the class see these (especially their signatures).

class Dog{
        BEGIN{ install "some_semantics", <<bark howl whine>> }
}



> -John

--abhijit

Reply via email to