Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Re^4: I don't understand UNIVERSAL::DOES()

by demerphq (Chancellor)
on Mar 09, 2007 at 20:57 UTC ( [id://604049]=note: print w/replies, xml ) Need Help??


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

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

  • Comment on Re^4: I don't understand UNIVERSAL::DOES()

Replies are listed 'Best First'.
Re^5: I don't understand UNIVERSAL::DOES()
by chromatic (Archbishop) on Mar 09, 2007 at 21:52 UTC
    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.

      The regex example just doesnt work. (Did you try it?) It wont work because UNIVERSAL::isa() doesnt know about "regexness", yes you can make sure that your qr// isa Regexp, but thats not a necessary condition to using a blessed qr// construct. Regexness is defined by whether the reference has regexp magic. Its yet another type-like attribute that is orthagonal to the rest. This is why i proposed the syntax I did, 'qr//' will never be a valid class name in perl, so its a perfect way to ask if something truely has a regexp magic.

      The other examples arent that useful because they fall into the same trap that UNIVERSAL::isa() did, that is confusing class names and types. Without recourse to a secondary routine like blessed() you can't distinguish an unblessed true hash reference from a blessed array reference that wants to mess up your code. AND to make things worse being a member of any of these classes does not actually say if your object supports a given dereferencing operation.

      In other words there is a clear difference between asking "does an object do what the class ARRAY does" and "can I dereference an object as an array". They are orthagonal concepts in perl that have no necessary relationship with each other, despite the fact that UNIVERSAL::isa() decided to merge them. (Arguably a design error much akin to ref() returning classnames on blessed objects).

      And again thats why I suggested the overload::Method like syntax for this, it separates out dereferencability from class membership in a way that lets you ask both questions, in a convenient and unambiguous way, so that people can do what they need to do without using a secondary routine. For instance all of your examples here really need to say

      use Scalar::Util; if (blessed($overloaded) && $overloaded->DOES( ... )) { ... }
      If that guard clause is needed (and it is) then the utility of UNIVERSAL::DOES drops considerably, if not more given that it currently is just a simple wrapper around UNIVERSAL::isa(). Wheras recoded to behave as I've outlined here and it would be able to replace almost every use of reftype(), blessed() and UNIVERSAL::isa() in non-serialisation code out there.

      I really want to see a unification of all the various type-like detection code into one routine and it seems to me that DOES is the best candidate for the job.

      Also, earlier in this thread you made a comment about ignoring various quirks of Perls design and pretending that we are working with something cleaner. In my opinion that approach doesnt lead to useful advances in the state of the art and in fact just leads to oversights. Like the fact that UNIVERSAL::DOES is currently useless unless complemented by the use of Scalar::Util::blessed(), which is hardly an advance over UNIVERSAL::isa(), more like a step backwards if anything. If you can swallow the fact that Perl isnt as clean as you want we can get a truely useful UNIVERSAL::DOES that scratches what I know to be some of your itches, and scratch the itches I have too, and finally introduce a type introspection tool that doesnt need helper routines from disparate modules spread throughout the core. Now that would be progress.

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

        I really want to see a unification of all the various type-like detection code into one routine and it seems to me that DOES is the best candidate for the job.

        Me too.

        However, tying that to "What kind of SV is this?" is a mistake.

        Yes, of course people can write bad DOES() methods. Yes, of course people can bless references into classes named after builtins and get the wrong answers. Yet people can also neglect to escape SQL from user input, build their own templating systems, build their own query parsers, forget to check the results of system commands, factor their code improperly, write ten-thousand line functions, use only global variables, and use symbolic references.

        I don't really care if bad programmers can abuse a feature if that feature makes it easier for decent and good programmers to do their jobs well.

        As I said, perhaps class names are the wrong role names for asking "does this entity support indexed access" or "does this entity support keyed access". That's fine.

        But please give me a little credit as the Perl 6 designer who's thought about this for a few years now--unifying types and roles is a good thing. Querying objects and types about their capabilities instead of their peculiar and accidental structural lineage is a very good thing. Unifying that behind an interface that allows encapsulation of the how and merely asks the question "do you?" is the right thing.

        I could never have convinced Larry and Damian, especially, if this were not so.

Re^5: I don't understand UNIVERSAL::DOES()
by ikegami (Patriarch) on Mar 09, 2007 at 21:16 UTC

    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.

      *isa= \&UNIVERSAL::isa;

      works great for me. I don't even have to "use UNIVERSAL" for this. There being no UNIVERSAL->import() makes some sense to me, but, as noted in Universally unimportant and overused, UNIVERSAL->import() appears to exist (and causes problems).

      Defining a special UNIVERSAL::isa() that can detect when it has been misused would be an acceptable compromise to me.

      - tye        

        The last paragraph was the most important, and it wasn't addressed. My fault, I didn't explain myself. Consider

        { package Foo; sub DOES { my ($self, $role) = @_; return 1 if ...; return $self->SUPER::DOES($role); } } Foo->DOES(...); # Line "A" UNIVERSAL::DOES('Foo', ...); # Line "B"

        Unless DOES does something non-intuitive, line "A" results in an infinite loop.
        Unless DOES does something non-intuitive, line "B" doesn't call the overridden DOES.

        Do we really want DOES to be that special? Having a function does (which calls DOES when appropriate) would avoid all this complexity.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://604049]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (2)
As of 2024-04-20 03:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found