kwaping has asked for the wisdom of the Perl Monks concerning the following question:

I have three modules - Base, User, and Client. User is a Base, and Client is a User (using use base for both). If I call __PACAKGE__ from a method in User, it says it's a User. This is great if I'm working with a User object, but not if I'm actually working with a Client object. I want User to know that it's really a Client.

My ultimate goal is to provide a generic method in User that can be used across User, Consumer, Admin, Client, etc. I need to be able to check what the ultimate class is in order to set variables specific to that class inside the User method.

Is this possible?

---
It's all fine and dandy until someone has to look at the code.

Replies are listed 'Best First'.
Re: Who am I? Inheritance question
by philcrow (Priest) on Mar 16, 2006 at 21:58 UTC
    If the "generic method" you have in mind is a class method it should start something like:
    sub generally_useful { my $class = shift; # ... }
    That $class will be the invoking class, not necessarily the __PACKAGE__ where generally_useful lives. This works for constructors.

    If the method is an instance method, it will be more like:

    sub instance_meth { my $self = shift; my $class = ref $self; }

    Phil

    Update: Added instance method example.

      sub instance_meth { my $self = shift; my $class = Scalar::Util::blessed $self; }

      My criteria for good software:
      1. Does it work?
      2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?

        Does this still work if you want $self to lie to instance_meth about what class it is? Can a mock object still be passed in here? I know ref() is overrideable but it's painful. How does a person handle that with Scalar::Util::blessed?

        ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

Re: Who am I? Inheritance question
by holli (Abbot) on Mar 16, 2006 at 22:15 UTC
    If I get you right you want to put code into the superclass that is dependend on it's subclass. This is generally a design flaw. the superclass should know nothing about it's subclasses.

    If you mean it the other way round, you just need to call isa(CLASS) on the object.


    holli, /regexed monk/
Re: Who am I? Inheritance question
by ikegami (Patriarch) on Mar 16, 2006 at 22:35 UTC
    How about
    if ($user->isa('Client')) { $user->method(); }
    or
    if ($user->can('method')) { $user->method(); }
Re: Who am I? Inheritance question
by lima1 (Curate) on Mar 16, 2006 at 22:09 UTC
    why do you want this if/else code in User?

    i think good OO design is when the baseclass does not know anything about its childclasses. you should implement the differences in the child classes.

    so provide an abstract method in User that the child classes implement. common code can be shared in a private method in user.

    or generalize your code for the generic method in User so that this method only requires some member variables that can be set in the childs constructors.

      or generalize your code for the generic method in User so that this method only requires some member variables that can be set in the childs constructors.

      Ah, that might do it, I'll try that.

      Update: Yep, that did it, thanks! I set our ($var1,$var2); in User then set $User::var1 = 'foo'; $User::var2 = 'bar'; in Client.

      ---
      It's all fine and dandy until someone has to look at the code.