in reply to Tracking Inheritance Directly due to Hybrid Methods

I don't have this module installed on my machine, so I can't test this, but what's wrong with calling the public constructor for Time::Piece from within the constructor of your subclass (thereby providing an instance to _mktime), and then reblessing the reference returned into your current package? You can do as much further initialization at that point as you want to without overriding the "private" method _mktime. It's worth noting as well that unless the documentation explicitly guards against it, you're perfectly free to interpret this as a "protected" method, which as a subclass your module may legitimately override.

Also, as long as the module containing the procedures (same as "functions"?) you need is in your ISA array, you won't need to do any manual traversal; this is automatically done in a leftmost, depth-first search of base classes when the method/function is not found in the current module. Now, granted, if they're functions then they'll expect to be called on a class name, not on a reference to a class instance, so your callers would need to call ref($yoursubclass)->somesub(), unless you intend to override all of these public methods as in

sub somesub { my ($this, $args) = @_; ref($this)->SUPER::somesub($args); }
But that would be a lot of redundant code. Perhaps I'm not following this part of your discussion.

Replies are listed 'Best First'.
Re: Re: Tracking Inheritance Directly due to Hybrid Methods
by mojotoad (Monsignor) on Jul 25, 2002 at 20:53 UTC
    what's wrong with calling the public constructor for Time::Piece from within the constructor of your subclass (thereby providing an instance to _mktime), and then reblessing the reference returned into your current package?
    I'd love to, but it's not that simple.
    1. It is not the only route of construction -- new objects are created either by new(), overloaded operators, gmtime(), or localtime(). The last two are procedural in nature and will not work if called statically via package name indirection (Time::MyPiece->gmtime()) since they expect either a reference or scalar seconds since epoch as first args. All of these eventually call _mktime() either as a method or procedure, so it seemed to make since to target the real constructor rather than each individual route.
    2. Even when we do target _mktime(), the blessings are hard coded as class 'Time::Piece'; we can rebless in a constructor, but we're stuck again with having to override every method that eventually calls _mktime() so that we can rebless. Not zesty.
    It's worth noting as well that unless the documentation explicitly guards against it, you're perfectly free to interpret this as a "protected" method, which as a subclass your module may legitimately override.
    Good point, I feel better about that then.
    Now, granted, if they're functions then they'll expect to be called on a class name, not on a reference to a class instance, ...
    This still passes the class name as a first argument -- as I mentioned, if the first argument is present and not a reference, then it expects it to be a scalar count of seconds since epoch, not a string representing the calling class name.

    Matt

      Okay, I think this is sinking in; gmtime and localtime are exported to your current module in such a manner that they can be called directly, that is, not on any package name or reference. Doesn't this mean then that even if you override _mktime you still have to override the exported functions so that they'll call your version of _mktime rather than the version in the package in which they were originally defined? I think you'd have to actually redefine it rather than override it, as in:

      no warnings 'redefine'; package Time::Piece; sub _mktime { ... }
      or
      sub Time::Piece::_mktime { ... }

      You know, the more I think about this, the more I think Time::Piece was written this way because it's not supposed to be subclassed ; ) Wouldn't using it as a mix-in for your modules give you all the flexibility you need? For what reason does the functionality you're looking for require an IS-A relationship to Time::Piece?

        Yes, the redefinition route might be the final result. Plus re-exporting gmtime() and localtime().

        As for the why of my desire for an isa relationship...I was building an "enhanced" timepiece that has some extended functionality...but I still wanted the behavior of Time::Piece, particularly the existing object methods, overloaded math operator functionality, stringification, etc.

        It was beginning to look like I was going to have to override everything in order to do that, which sort of defeats the purpose of subclassing. So I appealed to my fellow Brethren for better ideas.

        I think you have the right idea, though...given isa, I'm probably going to have to kiss all and redefine _mktime()

        Thanks for the sounding board,
        Matt