in reply to Re: I don't understand UNIVERSAL::DOES()
in thread I don't understand UNIVERSAL::DOES()

Personally I'd /really/ like to see DOES become more useful before 5.10 comes out. I think its a perfect opportunity to fix a bunch of problems. IMO, it should be usable in subroutine form, BUT still respect @ISA for blessed objects, it should handle the question of "can I dereference something in a particular way", and third it should answer "is this a compiled regex". I imagine that something like the following results

UNIVERSAL::DOES(sub{},'&{}') # return true UNIVERSAL::DOES(qr//,'qr//') # return true UNIVERSAL::DOES([],'@{}') # return true UNIVERSAL::DOES([],'The::Funky::Chicken') # return false UNIVERSAL::DOES([],'UNIVERSAL') # return false @Bar::ISA=qw(Foo); UNIVERSAL::DOES('Bar','Foo') # return true @Bang::ISA=qw(Foo); sub Bang::DOES { return 0 } UNIVERSAL::DOES('Bang','Foo'} # return false

I actually have a patch to universal.c for this behaviour on the brew right now.

---
$world=~s/war/peace/g

Replies are listed 'Best First'.
Re^3: I don't understand UNIVERSAL::DOES()
by chromatic (Archbishop) on Mar 09, 2007 at 18:48 UTC

    Instead of perpetuating hackish workarounds that take advantage of an implementation quirk that methods are just functions that take an extra parameter, why not fix the real problem and allow methods on all references via autobox?

    That's much more in line with how it works in Perl 6. It would be nice to keep the semantics of backported features as similar as possible.

      why not fix the real problem and allow methods on all references via autobox?

      Well, that would address /one/ of my concerns, that is it would not just die on an unblessed reference. But it doesnt address the other issues I mentioned.

      UNIVERSAL::DOES() is a perfect opportunity to address a host of typing related issues in Perl in one routine without burdening ourselves with yet another partial solution. Currently we have (at least) ref, Scalar::Util::reftype, Scalar::Util::blessed, UNIVERSAL::isa, overload::Method, and re::is_regexp(). Thats a lot of routines to know about, and to know how to use in concert properly. UNIVERSAL::DOES() seems like the perfect place to roll them all together into something sensible.

      Also it seems to me that DOES is the /correct/ place to ask "can I use $x as a subroutine reference", and not barf because $x is not UNIVERSAL::ISA($x,'CODE') but rather a blessed array reference that happens to overload code deferencing. DOES is about what one can use an object for after all.

      If we can get a sensible routine into core then people will use it, but if its another 2/3rds solution as so many of the existing routines are I bet it wont get used much at all. And will be in my eyes at least a missed opportunity. Especially as by writing it in C the code can be /much/ faster and accurate than any roll your own type detection code is.

      ---
      $world=~s/war/peace/g

        Well, that would address /one/ of my concerns, that is it would not just die on an unblessed reference. But it doesnt address the other issues I mentioned.

        Why not?

        my $regexp = qr/Some Regex/; warn "It's regexpable!" if $regexp->DOES( 'REGEX' ); my $subref = sub { ... }; warn "It's invokable!\n" if $subref->DOES( 'CODE' ); my $overloaded = Way::OverLoaded->new(); warn "It's indexable/keyable/invokable\n" if $overloaded->DOES( 'ARRAY +' ) && $overloaded->DOES( 'HASH' + ) && $overloaded->DOES( 'CODE' + );

        Those may not be the best role names, but I hope the idea is clear.

        UNIVERSAL::DOES() seems like the perfect place to roll them all together into something sensible.

        Do you really expect us to say UNIVERSAL::DOES everwhere?

        Do you plan to allow the export of DOES despite the many places where UNIVERSAL claims it's a mistake to have import at all?

        What if there's a package wants to use the DOES function *and* override DOES?

        Wouldn't it be better if your function was called does. If the argument is a class or an object, it would call the DOES method to permit overrides and roles.

Re^3: I don't understand UNIVERSAL::DOES() (automethodizing)
by tye (Sage) on Mar 09, 2007 at 16:38 UTC

    For those of us who can't just presume that 5.010 <= $], how about making UNIVERSAL::isa() check $_[0]->can("isa") if $_[0] is blessed and deferring to that sub if it isn't UNIVERSAL::isa()? Or do you also need to worry about Some::Class::isa() calling UNIVERSAL::isa() and is there no sane way to work around that even from C? Or is there some other reason that this wouldn't be a good idea?

    - tye        

      Or is there some other reason that this wouldn't be a good idea?

      I think that it could have backwards compatibility issues that would preclude it from happening in UNIVERSAL::isa(). Which is why ive been harping on about making DOES do the right thing.

      ---
      $world=~s/war/peace/g

Re^3: I don't understand UNIVERSAL::DOES()
by eric256 (Parson) on Mar 09, 2007 at 23:12 UTC

    Wouldn't it be better if the role names matched the ref? I.e. CODE,ARRAY,HASH,REGEX ? And could I see the patch? Just curiousity to see how something like that would be implemented, seems easy enough to implement in perl if you wanted and import it in.

    Here is my stab. I went with a DOES sub returning a list of roles that an object does, makes it easy to make them inheritable...(i.e.

    sub DOES { qw/log print/, shift->SUPER::DOES() }</code). Realy just fo +r my fun and amusment. ;) /me goes off to investigate the various ro +les modules</p> <code> use strict; use warnings; use Test::More qw/no_plan/; { package UNIVERSAL; sub does { return 1 if ref $_[0] eq $_[1]; #if ( eval qq/"@" . ref($_[0]) . "::DOES"/; if (UNIVERSAL::isa($_[0], 'UNIVERSAL') ) { if ($_[0]->can('DOES')) { return 1 if grep { $_[1] eq $_ } $_[0]->DOES(); } else { return 1 if $_[0]->isa($_[1]); } } return 0; } } sub say {print @_, "\n";} {package Foo}; is(UNIVERSAL::does(sub{},'CODE'), 1, 'Code Ref'); is(UNIVERSAL::does(qr//,'Regexp'), 1, 'Regex'); # return tr +ue is(UNIVERSAL::does([],'ARRAY') , 1, 'Array') ; # return + true is(UNIVERSAL::does([],'The::Funky::Chicken'),0 , 'Bad Class name') ;# +return false is(UNIVERSAL::does([],'UNIVERSAL'),0, 'Array isn\'t Univeral') ; + # return false @Bar::ISA=qw(Foo); is(UNIVERSAL::does('Bar', 'Foo'), 1, 'Bar does Foo'); # retur +n true {package Bang; @Bang::ISA=qw(Foo UNIVERSAL); sub DOES { qw(test) }; } is(Bang->does('Foo'), 0, 'Bang doesn\'t Foo'); + # return false { package A; sub DOES { qw/this or that/ }; } { package B; @B::ISA = qw/A/; sub DOES { qw/other/ }; } #B->test(); is(A->does('this') , 1, 'A does this'); # true is(B->does('that') , 0, 'B doesn\'t do that'); # false is(B->does('other'), 1, 'B does other'); # true

    ___________
    Eric Hodges

      This is what i have so far. Warning XS/Internals aware code. And no error checking on the rolename.

      UPDATE: An improved version of this code has been posted to p5p for further review, and maybe application in time for Perl 5.10.

      ---
      $world=~s/war/peace/g

      Wouldn't it be better if the role names matched the ref? I.e. CODE,ARRAY,HASH,REGEX ?

      No. For reasons i explained in my reply to chromatic. And 'REGEX' isnt a type. You will never see it returned from ref() or reftype(). Also, your code doesnt solve the "can i deref this item in a particular way" problem, nor the "does this reference contain regexp magic" problem.

      As for code, yeah, once i get it done ill post it. Currently its a work in progress.

      ---
      $world=~s/war/peace/g

        I wasn't thinking of those as types (and it wasn't meant as a final product, just an example of the way i was thinking about roles and does), I was thinking of them as roles since we are talking about does, and does talks about roles. If something reports that it does a role then its that somethings responsibility to insure it does. SO if i create a class that claims it does 'ARRAY' then it is my class's responsibility to insure that it can do everything that role entails. I see now reading your reply to chromatic that you aren't realy talking about roles at all which is where the disconnect is.

        If we assume that DOES is for roles, why not overload ->can to do what you want?. You do a role, but you can a method. So if you wanted to ask if you can dereference it as an array you ask if it <cdoe>->can($obj, '@{}')</code> to me that seems to follow your overloading style better as it doesn't imply that '@()' is a role, but actually that it is a method, which it is if you've overloaded it.


        ___________
        Eric Hodges