develooper Front page | perl.perl5.porters | Postings from March 2007

[PATCH] Extend functionality of UNIVERSAL::DOES() so it handles additional roles, and works in subroutine form.

Thread Next
From:
demerphq
Date:
March 11, 2007 05:46
Subject:
[PATCH] Extend functionality of UNIVERSAL::DOES() so it handles additional roles, and works in subroutine form.
Message ID:
9b18b3110703110545s9a9ae1dw7e14d461573f451f@mail.gmail.com
Currently the utility of UNIVERSAL::DOES is somewhat restricted. It
can't be safely used without also using Scalar::Util::blessed() as a
guard clause to ensure that the object being checked is in fact an
object. If you use the method form

  $obj->DOES('foo');

then you risk an error because $obj isnt blessed, and if you use the
subroutine form

  UNIVERSAL::DOES($obj,'foo');

and $obj isnt blessed then you end up with a different error, (can't
call method 'isa' on an unblessed reference).

I have fixed this problem by making UNIVERSAL::DOES($item,$role) when
used in subroutine form work in DWIM fashion. When $item is an
unblessed reference, then it delegates to UNIVERSAL::isa() via
subroutine call. When $item is a classname of or object belonging to a
class that overrides DOES then the core routine will delegate to the
custom one.  The only drawback of this apprach is that the any DOES
implementation that needs to delegate to the UNIVERSAL::DOES routine
must pass an additional flag to prevent it from just delegating back.

At the same time Id like to see UNIVERSAL::DOES() also answer the
question "is this item a regex" and "is this item dereferencable in a
given way" in a safe way as the core would answer the question itself
when trying to do the operation. For this purpose I've added support
for the additional roles '${}', '@{}', '%{}', '&{}', '*{}', and
'qr//', this merges behaviour that can be obtained by an adept use of
Scalar::Util::blessed(), Scalar::Util::reftype(), overload::Method(),
and UNIVSERAL::isa(). This also distinguishes the question "is the
object blessed into the class 'ARRAY'" and is this object
dereferencable as an array. Which are. unfortunately, due to
historical reasons not the same question.

The end result is that you can do stuff like this:

  if ( UNIVERSAL::DOES($obj,'@{}') ) {
     print "Object when derefenced as an array returns: @$obj";
  }
  if ( UNIVERSAL::DOES($obj,'qr//') ) {
     print "Object is a compiled regex!";
  }
  if ( UNIVERSAL::DOES($obj,'ARRAY') ) {
     print "Object claims it is an ARRAY";
  }
  sub Foo::DOES { 1 }
  if ( UNIVERSAL::DOES('Foo','named-role') ) {

All original tests still pass with this change, and the patch includes
another 20 tests.

Note that the end result of this patch for existing code is that
people can replace UNIVERSAL::isa() in all usages with
UNIVERSAL::DOES(), with the only possibility of breakage being code
that deliberately wants to avoid an objects isa() method lieing to
them. Which is pretty much only deep-voodoo stuff like serialization
code.

This patch requires a regen after it is applied.

cheers,
Yves
ps: I thought about whether DOES should croak if a special role is
requested and we dont support checking for it. I can see both sides of
whether it should throw an error.

cheers,
yves
-- 
perl -Mre=debug -e "/just|another|perl|hacker/"

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About