Skip to content

Instantly share code, notes, and snippets.

@autarch
Last active August 29, 2015 14:07
Show Gist options
  • Select an option

  • Save autarch/de572363115de4239b3a to your computer and use it in GitHub Desktop.

Select an option

Save autarch/de572363115de4239b3a to your computer and use it in GitHub Desktop.
Proposed API for better overload support in Moose
=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