Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Global Super Class (equivalent of java.lang.Object)

by arunhorne (Pilgrim)
on Sep 26, 2006 at 11:37 UTC ( #574909=perlquestion: print w/ replies, xml ) Need Help??
arunhorne has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I have a question on good design practice/pattern that I would appreciate the inputs of others on...

Having started a new project from scratch I will be using Perl to implement an object based hierachy. If I look at a language such as Java I will see a class called java.lang.Object which is otherwise known as the "global superclass". The purpose of this class among other things is to provide some common functions (e.g. 'toString()' which provides a string representation of an instance which is useful for debugging).

My question, if you have not already guessed, is this. Although Perl does not explicitly provide such a global superclass (or correct me here if I am mistaken), it would seem like good design practice to create one called 'Object' and have all other classes inherit from it. Initially it may have no functions except 'to_str()', however, it provides a level of future proofing. Does anyone have any experience or advice on such an approach?

Kind regards,

____________
Arun

Comment on Global Super Class (equivalent of java.lang.Object)
Re: Global Super Class (equivalent of java.lang.Object)
by Corion (Pope) on Sep 26, 2006 at 11:42 UTC

    There is UNIVERSAL, but adding methods to it is a generally bad idea, because you affect every class, and especially classes using AUTOLOAD can be tripped up by this.

    Every Perl class has an implicit toString method, invoked by the print function. If you want to overload those, you likely want overload.

    Even if you go the route of polluting UNIVERSAL, there is still the problem that 99.9% of the remaining Perl codebase doesn't know or support your variation.

Re: Global Super Class (equivalent of java.lang.Object)
by chorny (Scribe) on Sep 26, 2006 at 11:53 UTC

    perl has class that is parent of all classes. It is called Universal. type `perldoc Universal` in your shell. You can insert any function in it. But you don't need to. Perl object model is much flexible relative to strict Java's. AFAIK, Java does not have multiple inheritance. Perl does.

    There is no need for Univeral::as_string (Perl equivalent of toString()) method as you can simply call as_string of any object if his class supports it (and to know that you can use Universal::can). You can think that as_string is an interface.

      No, not "Universal". It is UNIVERSAL. Classes are case sensitive.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

Re: Global Super Class (equivalent of java.lang.Object)
by herveus (Parson) on Sep 26, 2006 at 12:43 UTC
    Howdy!

    Java and Perl approach things differently. Let's look at the methods Object provides...
    JavaPerl
    clonenothing standard; depends on object model being used
    equals==
    finalizeDESTROY
    getClassref
    hashCoderefaddr
    notifynot sure; thread related
    notifyAllnot sure; thread related
    toString""
    waitnot sure; thread related
    ?UNIVERSAL::can
    ?UNIVERSAL::isa
    ?UNIVERSAL::VERSION

    As you can see, Java doesn't stuff much into Object, but those things are deemed necessary for every object to be able to do. UNIVERSAL has some introspective methods; the other things that have to be in a class (in Java) are language features, either as operators or built-ins, and are mostly all applicable to non-object-oriented programming as well as OO.

    If your project has some "universal" things that all the objects need to do, then by all means define a base class for all of your objects. That lets you make your system behave the way you need it to while not (potentially) breaking it for code you include from elsewhere.

    yours,
    Michael
Re: Global Super Class (equivalent of java.lang.Object)
by Ovid (Cardinal) on Sep 26, 2006 at 13:16 UTC

    Don't put anything into the UNIVERSAL class as you may break a bunch of code already installed on your system. Instead, create your own "global super class" and have all of your base classes explicitly inherit from that. You'll get the benefit you want and not break anything else.

    Cheers,
    Ovid

    New address of my CGI Course.

Re: Global Super Class (equivalent of java.lang.Object)
by ides (Deacon) on Sep 26, 2006 at 14:25 UTC

    I agree that putting methods into UNIVERSAL is a bad idea. However, there isn't anything wrong with having a base class for like objects. MyApp::Base::User for differnet types of users, etc. You get the idea.

    Personally, I find it very rare that I have any methods that I want to provide for all objects in an application that can't be provided without the need for such a generate base class. For example, if I wanted to toString() an object I would just use Data::Dumper on the object itself.

    Frank Wiles <frank@revsys.com>
    www.revsys.com

Re: Global Super Class (equivalent of java.lang.Object)
by InfiniteLoop (Hermit) on Sep 26, 2006 at 15:30 UTC
    Greetings,
     Generally, over a period of time, you tend to abuse the root class. In my current project I see that we tend to "use" many modules, in the root class, that are not neccessary in most of the places, thereby increasing the memory.

      Although you could create a single root class (like Objective-C's NSObject), try to have specialized root classes (maybe a root class for all your UI's and one for your model classes) which would inherit from your single root class.
Re: Global Super Class (equivalent of java.lang.Object)
by jimt (Chaplain) on Sep 26, 2006 at 16:39 UTC

    This was one of my original design goals when I created Basset. I wanted one object to bind them all.

    Well, slightly earlier than that, I just wanted a persistent object store, ala Class::DBI or Tangram or whatever else was popular at the time. But the immediate problem I had was that the peristence layer didnt need to have anything in common with any other objects I was using or creating. Yes, yes, I could've reverse engineered and cloned out the API for one of them, but it really would have been two APIs (my cloned copy, and the original one), which I didnt care for.

    So in a fit of enthusiasm, I created Basset::Object and haven't looked back. This is where I stuck all of the global stuff that all of my objects were going to need. So the constructor goes there, the default initializer goes there. Most importantly - error handling goes there. Methods for adding attributes go there. That way, if you change your under lying object type, you just change the method to add new attributes (which is a closure generator around the actual reference access), and everything updates for free. Note - it's not easy to use this approach if you want to vary up the internals for subclasses. So having a hashref inherit from an arrayref is still difficult, but changing all your stuff to an arrayref is relatively easy.

    A few important helper methods (loading packages, an abstract factory, a copier) and some other crap that I don't use a whole lot. Pay careful attention to the "crap" part. It's really really tempting to put stuff in there that just doesn't belong, for simplicity's sake. I had the methods in there to do html & cgi escaping for a long time, 'cuz it was easy. I finally got rid of them a few months back. I still have stuff in there for simple time strings. That's debatable whether it should be present. Basically, you need to police your root class vigorously. If theres any doubt that it should be there, then hold off. Think it over more. If youre positive that absolutely everything anywhere in the world could use it, then think about it some more before putting it in. An unpoliced root class quickly becomes a function bucket and largely useless.

    And the results? They're amazing. I've used it to build and provide for myself an API. If you're using anything in Basset, it's designed to work the same way. All your objects are created the same way, they all report errors the same way, they all get initialized the same way. It's all consistent1. I never end up with code where the persistence layer throws an exception inside the template which would otherwise return an error code. Everything always is where I think it will be.

    Encapsulation is the other big advantage. For example, I do have a ->dump method which is just a wrapper around Data::Dumper. Utterly trivial, but it standardized everything in my world to dump in one and only one way. If you want to dump something else in a non-standard way? Go ahead and do it, but then it's your responsibility to deal with. But if I want to change the global dump method to not use Data::Dumper? Easy as pie. One method, everything gets it automatically.

    I've gone to great pains over the years to define the root object to be as abstract as possible. This is so I can easily drop it into disparate situations and have it just work. You don't edit it, you change your root object in your system and make modifications there. You don't inherit from it, you inherit from your abstract object type (whatever it is you've defined in basset that you're using in your system). I strongly wanted to enforce a set of rules, but I wanted to make sure those rules were as flexible as possible.

    For example, I use error codes everywhere (though I am strongly debating jumping to exceptions, finally). And Basset is set up to work that way. But if you want to use exceptions? Flip a flag and you've got exceptions. All of your code remains the same.

    I'll hop down off of my advertising soapbox now. The point I'm trying to make is that its been wildly successful for me in standardizing everything I work on. I don't need to worry about figuring out how housekeeping stuff is handled, that's all dealt with for me. I can worry about important things. I think that's the strongest argument for any of the frameworks using abstract root objects. Let the framework worry about the nitty gritty, you've got real code to write.

    And, in the spirit of my The history of a templating engine, I'll just point out to be careful what you're getting into if you write your own. The benefits are tremendous, as long as it works for you. But it will also become the most keyly critical piece of software you have anywhere. If everything inherits from it, then it has to work flawlessly 100% of the time. For me, Basset::Object is my most tested module, with somewhere around 95% coverage (I think). Changes to it can be tedious as they may have to propogate out to my entire world, so I'm always slow to move on changes to the external API. I'm slow to move on internal changes as well, due to the potential to break everything.

    So proceed cautiously, but I highly highly recommend this approach. The potetntial gains are amazing. I'm pleased as punch.

    1 Yes, I am aware of the irony of a system thats completely internally consistent, but not really consistent with the way a lot of the rest of the perl world works. Shaddup.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://574909]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (3)
As of 2014-10-25 09:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (142 votes), past polls