Last active
August 29, 2015 14:07
-
-
Save autarch/de572363115de4239b3a to your computer and use it in GitHub Desktop.
Proposed API for better overload support in Moose
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| =pod | |
| =head1 NAME | |
| Moose Overloading - Design sketch for better overloading support in Moose | |
| =head1 SYNOPSIS | |
| # These are Class::MOP::Overload objects | |
| for my $overload ( $meta->get_all_overloaded_operators() ) { | |
| say $overload->operator(); | |
| say $overload->is_anonymous; | |
| if ( $overload->has_method() ) { | |
| # A Class::MOP::Method (or Moose::Meta::Method?) object | |
| my $meth = $overload->method(); | |
| say $meth->name; | |
| } | |
| elsif ( $overload->has_coderef() ) { | |
| say 'has anon coderef as implementation'; | |
| } | |
| else { | |
| say 'no implementation'; | |
| } | |
| } | |
| =head1 DESCRIPTION | |
| The basic problem with Moose's current overloading support is that it equates | |
| an overloaded operator with a method. This is just wrong. There is no 1-to-1 | |
| correspondence between an overloaded operator and a method. | |
| In reality, an overloaded operator can have one of four implementations: | |
| =over 4 | |
| =item * A method name and a corresponding method | |
| use overload q{""} => '_stringify'; | |
| sub _stringify { ... } | |
| In this case the C<Class::MOP::Overload> object would return true for | |
| C<has_method()> and the C<method()> method would return an appropriate | |
| C<Class::MOP::Method> object. The C<is_anonymous> method will return false. | |
| Note that that the method can be implemented by a parent class, so the | |
| returned method object may not be associated with the same package as the | |
| overload (and that's ok). | |
| =item * A reference to a named sub | |
| use overload q{""} => \&_stringify | |
| In this case there is no method associated with the overload, but there is a | |
| subroutine. The C<Class::MOP::Overload> object will return true for | |
| C<has_coderef()>, and the coderef itself will be returned by the C<coderef()> | |
| method. This will return a raw coderef, not an object. The C<is_anonymous> | |
| method will return false. | |
| =item * An anonymous code reference | |
| use overload q{""} => sub { $_[0]->name() } | |
| In this case there is no method associated with the overload, but there is a | |
| subroutine. The C<Class::MOP::Overload> object will return true for | |
| C<has_coderef()>, and the coderef itself will be returned by the C<coderef()> | |
| method. This will return a raw coderef, not an object. The C<is_anonymous> | |
| method will return true. | |
| =item * A method name and no corresponding method | |
| use overload q{""} => '_stringify'; | |
| # no _stringify method | |
| This is allowed by the overload pragma. While this probably be plain broken in | |
| non-Moose Perl code, this actually makes sense in a Moose role. We could | |
| simplify require that all consuming classes implement a C<_stringify()> | |
| method. | |
| In this case both the C<has_method()> and C<has_coderef> subs return | |
| false. The C<is_anonymous> method will return false as well. | |
| =back | |
| =head1 Class::MOP::Overload API | |
| The C<Class::MOP::Overload> class will provide the following methods: | |
| =head2 Class::MOP::Overload->new(...) | |
| This will accept the following parameters: | |
| =over 4 | |
| =item * operator | |
| This is a string describing the operator, such as C<""> or C<0+>. Required. | |
| =item * method_name | |
| If this overload is implemented by a method, this is its name. Optional, but | |
| this or C<coderef> must be passed. | |
| =item * coderef | |
| If this overload is implemented by a coderef, this is it. Optional, but this | |
| or C<coderef> must be passed. | |
| =item * method | |
| A C<Class::MOP::Method> object for the implementation method. Optional. | |
| =item * associated_metaclass | |
| The meta-object for the class or role where this overload was | |
| declared. Optional. | |
| =item * original_overload | |
| This will be work just like original_method does for method | |
| meta-objects. Optional. | |
| =back | |
| =head2 Info methods | |
| The following methods will exist for getting info about the overload: | |
| =over 4 | |
| =item * $overload->operator() | |
| =item * $overload->has_method_name() | |
| =item * $overload->method_name() | |
| Could return C<undef>. | |
| =item * $overload->has_method() | |
| =item * $overload->method() | |
| Could return C<undef>. | |
| =item * $overload->has_coderef() | |
| =item * $overload->coderef() | |
| Could return C<undef>. | |
| =item * $overload->is_anonymous() | |
| Returns true when the overload is implemented by an anonymous coderef. | |
| =item * $overload->associated_metaclass() | |
| =item * $overload->original_overload() | |
| Could return C<undef>. | |
| =back | |
| =head2 $overload->attach_to_class() | |
| Works just like the method of the same name in C<Class::MOP::Method>, except | |
| that attaching an overload to a class will enable overloading in that class. | |
| =head2 $overload->detach_to_class() | |
| Works just like the method of the same name in C<Class::MOP::Method>, except | |
| that attaching an overload to a class will disable overloading in that class | |
| if it's the last overloaded operator for the class. | |
| =head2 $overload->clone() | |
| Works just like the method of the same name in C<Class::MOP::Method>, and | |
| preserves the original object in the clone as the C<original_overload()>. | |
| =head1 API FOR THINGS THAT CAN HAVE OVERLOADS | |
| Both roles and classes will share this API. This API will pretty much work | |
| exactly like it does in current Moose HEAD, except that the introspection | |
| methods will return C<Class::MOP::Overload> objects instead of | |
| C<Class::MOP::Method::Overload> objects. | |
| =head1 OTHER CHANGES | |
| The C<Class::MOP::Method::Overload> class will be removed entirely. | |
| Inasmuch as possible, the handling of overloaded operators in roles will be | |
| exactly like methods, including in the application of overloads to consuming | |
| classes and roles. | |
| =head1 IMPLEMENTATION NOTES | |
| I'm inclined to use C<Devel::OverloadInfo>. If we really don't want to add the | |
| dep I suppose I could the relevant bits into our code base. | |
| =cut | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment