in reply to Is "ref $date eq 'ARRAY'" wrong?

Ow my god! What a confusion that some monks are making here!

First, doesn't exists the object type ARRAY or the package ARRAY, ok?!

ref(), like the name tell, is just for reference type! Soo, if you make ref() you can have returned the reference for the data type, SCALAR, ARRAY, HASH, GLOB, CODE and REF.

What we need to remember is that an object make a reference to a package, soo ref() also return the name of the package, or where this object is blessed. But the name of the package, let's say FOO, is something very different of the data types SCALAR, ARRAY, HASH, GLOB, CODE. Remember, ref() only take care about reference types!

Soo, if some crazy people say to you to not use ref() to see if you have an ARRAY ref, or an normal SCALAR/string, forget! Actually, ref() was created to be used exactly in this case!

About isa, you should use it for objects, and only for objects! UNIVERSAL, as POD say, is the base "class" for all the objects, since all of them "extends" UNIVERSAL, actually, all of them have UNIVERSAL at @ISA by default.

Soo, this code is trying to know if you have an object that extends the package/class ARRAY, or if it has ARRAY in the @ISA tree, as the name say, isa():

UNIVERSAL::isa($date, 'ARRAY')
It will work for a reference too, but was not made for that! Soo, if some day some other crazy people make the module/class ARRAY, and than build another module that extends it, let's say ARRAY::EvenCrazy, isa($obj_array_crazy , 'ARRAY') will return true too!

Now about ref() with objects, the only case that you should use it, is when you explicity want an object blessed in the package FOO, soo is rigth to write:

if ( ref($obj) eq 'FOO' ) {...}

Still on isa(). If you want to accept an object reference, and use it's internal type (ARRAY, HASH, CODE, GLOB) as a non blessed reference/data, you can use isa:

if ( UNIVERSAL::isa($blessed_in_foo , 'HASH') ) { print "Is an HASH object!\n" ; }
But I never saw that and I think that this is very wrong, specially in OO style, since you are accessing/changing it's internal structure/attributes directly, and not by methods!

Note that be "paranoic" is the worst thing that you can make in your code. You will create a lot of bugs and make your code slow! You have to use what was created for, to be used for each need, this is how we create cool codes. ;-P

Graciliano M. P.
"Creativity is the expression of the liberty".

Replies are listed 'Best First'.
Re: Re: Is "ref $date eq 'ARRAY'" wrong? What a mess!
by Anonymous Monk on Dec 20, 2003 at 05:23 UTC
    from man perlobj:
           isa(CLASS)
               "isa" returns true if its object is blessed into a subclass of
               "CLASS"
    
               You can also call "UNIVERSAL::isa" as a subroutine with two argu-
               ments.  The first does not need to be an object or even a refer-
               ence.  This allows you to check what a reference points to, or
               whether something is a reference of a given type. Example
    
                   if(UNIVERSAL::isa($ref, 'ARRAY')) {
                       #...
                   }
    
               To determine if a reference is a blessed object, you can write
    
                   print "It's an object\n" if UNIVERSAL::isa($val, 'UNIVERSAL');
    
    

    UNIVERSIAL::isa( $thing, "CLASS" ) is a far superior method than ref( $thing ) eq 'CLASS', since the latter does not cater for inheritance.

    But I never saw that and I think that this is very wrong, specially in OO style, since you are accessing/changing it's internal structure/attributes directly, and not by methods!

    try reading perldoc perlobj!
    calling UNIVERSAL::isa does not "access/change internal structure/attributes" -- it is the OO equivalent of a class/static method call in java or c++.

      But 'ARRAY' is not a class. When ref() returns 'ARRAY' it is describing the array reference (which is what the question was posed about). The fact that UNIVERSAL::isa returns 'ARRAY', IMHO, is a bad design. It should return undef instead, since 'ARRAY' is not a class, therefore it doesn't inherit from UNIVERSAL or have an @ISA associated with it.

      If one really wanted to argue this, it could be said that since you must bless a reference, that all references then are essentially base classes, but I have not seen anything in the Perl OO documentation to indicate this as an acceptable point of view. And this contradicts the idea of UNIVERSAL which is and does function as the Perl base class.

      Personally I do not like single inheritance, or the idea of deep inheritance heirarchies steming from a single base class. They are fragile and contradict the idea of encapsulation since sometimes one needs to navigate deep into a heirarchy to find a method implementation. Anyone who has navigated a javadoc will understand what i mean. I have always felt that multiple inheritance and class composition (through a variety of means) are far superior, along with the Eiffel idea of flattened class views (where the heirarchy is flattened for the documentation so that all methods are viewable as members of the top level class).

      And while you are correct that this does not truely reveal the internals of any object, the usage of UNIVERSAL with the double colon does subvert the OO syntax '->' and essentially turn UNIVERSAL into a plain vanilla Perl package/module. By subverting the '->' method call syntax you are bypassing the built in method resolution and essentially bypassing the inheritance heirarchy (which of course doesnt really matter since UNIVERSAL is the base class anyway).

      I dont agree either that this is equivalent to calling a class or static method. I dont see Perl as having true equivalents of static methods, and a class method (at least the way i view them) is a method you call through the class an not through the instance. In other words it doesnt require an instance to be called. But you should still call it with the '->' method invocation syntax.

      I think it should be kept in mind that an array reference (ARRAY) is not a class (or even blessed for that matter), and hence really shouldn't be treated as such (IMHO of course).

      -stvn

        why do you think UNIVERSAL::isa returning ref type is a bad design (the perl developers obviously don't think so...)? using UNIVERSAL::isa to establish ref type allows one to turn the array ref that used to be passed to a method into a blessed object (preferably a tie in this case to intercept internal data access) that lists the fictitious class 'ARRAY' as a (completely abstract) superclass (or interface if you prefer).

        i do not think this is evidence of a bad design at all. it is just necessary to relax one's OO prejudices/convictions a little (which for perl OO, shouldn't be difficult ;-) ). on the contrary, i feel the 'ARRAY', 'HASH', etc pseudo classes ought to be used as marker interfaces (think java's Serialisable or Cloneable) to indicate the capability to be deferenced as a variable of that type (which, if the object supports a tie interface or has overloaded magic is really a method call in disguise). in other words, if isa( $thing, "ARRAY" ) returns true then $thing can be used as if it were a native array, regardless of exactly what $thing is, or how it implements array retrieval/storage. hooray for encapsulation *and* some nice parametric polymorphism as well.

        and FWIW, using isa() in this manner is used in quite number of cpan modules.

      As I said, ref() should be only used with objects if you really want, explicity, an object blessed in the class FOO, soo, without care about inheritance.

      > > But I never saw that ...
      > try reading perldoc perlobj!

      I know that this is possible, as I show in the previous node, what I said is that I never saw this in use! I never saw a code that want's to use the internal object data, HASH, ARRAY,... as a normal data! And I think, that shouldn't be used, since this is not a good thing when we are talking about OO.

      Graciliano M. P.
      "Creativity is the expression of the liberty".

        As I said, ref() should be only used with objects if you really want, explicity, an object blessed in the class FOO, soo, without care about inheritance.

        it is poor form to mandate a specific class name for anything except establishing capability. to establish whether a thing can perform only 1 or 2 methods, UNIVERSAL::can( $thing, "doFoo") is more flexible than UNIVERSAL::isa( $thing, "Fooable") besides.

        I know that this is possible, as I show in the previous node, what I said is that I never saw this in use! I never saw a code that want's to use the internal object data, HASH, ARRAY,... as a normal data! And I think, that shouldn't be used, since this is not a good thing when we are talking about OO.
        try: grep -nr 'isa' /usr/lib/perl | grep -e 'ARRAY' -e 'HASH'

        HASH, ARRAY, etc are not internal object data, they are type names in the same way that an object's class name is a type. If i wished to replace all array refs in my code with objects of my shiny new sorted array class with its TIEARRAY interface, i could change only the calling method (to create the object instead of the array ref), put 'ARRAY' into @MySortedArray::ISA as a pseudo-class (read: interface or capability to act as an array), then any code which used UNIVERSAL::isa( $thing, 'ARRAY' ) to establish that $thing could be dereferenced as an array (through its tie interface) would continue to work unchanged, but code using ref( $thing ) eq 'ARRAY' would break and need recoding. and in my company's 170,000 line perl app, recoding hundreds of methods because of bad coding is A Bad Thing and a huge PITA.

      damnit, forgot to login. :-$