in reply to RFC: DBIx::Iterator
Why UNIVERSAL::isa? Do you expect people to pass in blessed references? Do you want to forbid tied variables?
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: RFC: DBIx::Iterator (isa)
by tye (Sage) on May 12, 2007 at 05:29 UTC | |
Why UNIVERSAL::isa? Do you expect people to pass in blessed references? Do you want to forbid tied variables? You confuse me. Some of the advantages of isa are that it doesn't forbid blessed references and it doesn't forbid tied variables. One of the problems with using isa() as a function instead of as a method is that items that pretend to be some type of data structure via overloading are not detected by direct use of UNIVERSAL::isa() alone. One way to help isa() is for such classes to implement their own isa() method. Unfortunately, that work-around is often quite inconvenient for code like above to make use of (because $ref->isa("HASH") is most likely to just die, even though it works better for this one case). A much better (IMHO) work around would be for such an overloading class to do push @ISA, "HASH"; so that UNIVERSAL::isa( $ref, "HASH" ) would be true. Doing a tiny bit of testing, I see that UNIVERSAL::isa() is somewhat pickier than I assumed and to make this work one must also do something to create the "HASH" package, for example, { my $no_op= @HASH::ISA; }. So I consider UNIVERSAL::isa() to be a "best practice" because it gets (as near as I can tell) all but the one rarest case right, it is very simple and easy to understand (doing *isa= \&UNIVERSAL::isa; makes it even nicer), and that one rarest case is nearly trivial to make work as well. A patch to overload.pm do this push @ISA, "HASH" and create the HASH package (etc.) when appropriate would be well worthwhile, IMHO. I apologize that I won't be attempting such a patch any time soon for a number of reasons. I hope I got that all correct. :) Update: And let me address one potential complaint that I've seen before. One other aspect of UNIVERSAL::isa() is that you can use the technique I gave above to lie, intentionally making UNIVERSAL::isa() incorrectly return a true value for your objects. This aspect does not bother me because "Doctor, it hurts when I do this", that is, if you want to go out of your way to intentionally break my simple code, I just don't care. More importantly, such an ability can prove extremely useful for some of those edge cases you run into when writing unit tests and trying to get full code coverage. So I consider this aspect to be a feature. Note that you can also (probably) cheat in the other direction as simply as doing *UNIVERSAL::isa= sub { ... };. I can certainly see the point in trying to prevent people from accidentally creating a class that breaks my simple code. I think it folly to try to prevent people from intentionally trying to break such code. So it'd be really cool if overload.pm were "fixed" to co-operate with this technique. If I saw some other candidate for "best practice" here that was as close to "right" and as available yet didn't require this somewhat hackish trick, then I'd be pushing it instead. All of the alternatives have much worse draw-backs, I believe. - tye | [reply] [d/l] [select] |
by chromatic (Archbishop) on May 12, 2007 at 06:16 UTC | |
So I consider UNIVERSAL::isa() to be a "best practice" because it gets (as near as I can tell) all but the one rarest case right... Unfortunately, the function use of isa() and can() has been deprecated in bleadperl for at least a year. It doesn't answer the question appropriately. It's a hack. It relies on an accidental implementation detail of how method storage works in Perl. In my mind, the right solution is to patch overload to answer DOES() appropriately, which has the benefits of being the right question, giving the right answer, and not breaking methods. (Life would be even more pleasant with autobox in the core at that point; then reftype() would be unnecessary before calling DOES().) | [reply] [d/l] [select] |
|
Re^2: RFC: DBIx::Iterator
by runrig (Abbot) on May 12, 2007 at 04:49 UTC | |
Why UNIVERSAL::isa?Because nobody has suggested anything better yet or convinced me otherwise...I've seen some of the debates on UNIVERSAL::isa vs. ref() vs. Scalar::Util:reftype(), but not recently, and I don't recall what all the pros and cons are, and I'm not sure if there was any absolute best solution. Got any suggestions? | [reply] |
by chromatic (Archbishop) on May 12, 2007 at 06:09 UTC | |
My best suggestion is to accept only one type of argument so you don't have to perform the check at all. If that's not feasable, I suggest to dereference the reference appropriately inside an eval block. Otherwise you end up with a huge chain of tests just so that you don't miss all of the possibilities (non-reference, reference of the wrong type, reference of the right type, blessed reference, tied object, blessed reference of the wrong type with overloading, blessed reference of the right type with overloading). Philosophically speaking, using UNIVERSAL::isa() to check for structural typing in Perl is perilous because Perl uses a nominal typing system (or behavioral, but no one ever talks about that). Sometimes the only way to know if you can do a thing is to do it and see if anything breaks. | [reply] [d/l] |
by runrig (Abbot) on May 12, 2007 at 16:16 UTC | |
| [reply] [d/l] |
by chromatic (Archbishop) on May 12, 2007 at 23:21 UTC | |
by runrig (Abbot) on May 18, 2007 at 18:33 UTC | |