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

I am writing an extension to (or subclassing, or whatever) MathML::Entities - MathML::Entities::Approximate. I would like my package four things:

  1. Perform a lookup on a data hash defined within itself
  2. Pass on any function/method calls not defined in MathML::Entities::Approximate up to MathML::Entities (preferably without having to do:
    sub name2numbered {return MathML::Entities::name2numbered(@_)}
  3. Load MathML::Entities for the user, even though they only ask for MathML::Entities::Approximate
  4. Extend the %ENTITIES hash in MathML::Entities [defined with my %ENTITIES = (.....) ]

MathML::Entities exports two funtions automatically, and I want to be available even though only use MathML::Entities::Approximate; has been called.

  1. This is easy - done that.
  2. I read that this should just be a case of a use base MathML::Entities... but it's not happening. I've also tried use MathML::Entities; our @ISA = qw(Exporter MathML::Entities); - to no avail: the exported function from MathML::Entities is not available
  3. This is causing me problems. %ENTITIES is defined as a my variable in MathML::Entities - so how to I access it and add to it such that MathML::Entities functions can access the new data.

Any pointers/tips/advice/hand-holding/etc...?



-- Ian Stuart
A man depriving some poor village, somewhere, of a first-class idiot.

Replies are listed 'Best First'.
Re: Modifying/extending a superclass' data
by Zaxo (Archbishop) on Nov 17, 2005 at 12:46 UTC

    Unfortunately (though many think it a feature), your point 3. is correct. The declaration of %ENTITIES as a lexical gives it file scope only. Without some sub forming a closure by returning it or a reference to it, it is invisible outside the file.

    There is a half-measure you can take. The functions exported by MathML::Entities need not be imported, and you can define your own %ENTITIES and functions like so:

    package 'MathML::Entities::Approximate'; use MathML::Entities (); # explicit no-arg stops import my %ENTITIES = ( foo => '&x000042', ); sub _convert2numbered { my $reference = shift; $reference =~ /^&([a-zA-Z0-9]+);$/; my $name = $1; # above copied from MathML::Entities return exists $ENTITIES{$name} ? $ENTITIES{$name} : MathML::Entities::_convert2numbered($reference); } # etc.
    Note that the _convert2numbered code copied from M::E is not very good. It assumes the match succeeded and blithely goes on to work with $1. Bad Practice. In its defense, such a match has already succeeded before this function is called, but that's a thin reed to hang on to if you want robust subclassible code.

    Another choice would be to just copy the MathML::Entities code to your module and modify it there. That's not very different from the above code, and probably simpler.

    After Compline,
    Zaxo

      Another choice would be to just copy the MathML::Entities code to your module and modify it there.

      Indeed - or I could simply hack the changes I want into M::E itself (which I have done on my workstation, for development purposes).... but that kinda defeats the purpose of having proper Packages <grin />)



      -- Ian Stuart
      A man depriving some poor village, somewhere, of a first-class idiot.
        I would provide some set of accessor functions to, at least, add entities to %ENTITIES. Then, I would submit the patch back to the author along with some tests. Remember - in OSS, if you want something done, the quickest way is to do it yourself. That's why you have the code.

        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?
Re: Modifying/extending a superclass' data
by xdg (Monsignor) on Nov 17, 2005 at 13:00 UTC

    These question suggest that there are some basics about Perl OO that you're missing. You might want to see Perl Object Oriented Meta-Tutorial for pointers to where to start. For example, to subclass, you'd need to make sure the argument to base is in quotes:

    use base 'MathML::Entities';

    However, for your question about making functions available, you just need to make sure the functions are imported in the first place, and then specify them to be exported. For that, you have to do it longhand, you can't use base as that doesn't import any functions.

    package MathML::Entities::Approximate; use strict; use MathML::Entities qw(function1 function2); # import the desired fun +ctions use vars qw( @ISA @EXPORT ); @ISA = qw( MathML::Entities Exporter); @EXPORT = qw( function1 function2 ); # re-export them

    Unfortunately, to the last point, if %ENTITIES is a "my" variable in MathML::Entities, you can't access it directly without "breaking the rules" using something like PadWalker.

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

      These question suggest that there are some basics about Perl OO that you're missing.

      Absolutely! I've spent two years in JavaLand, and forgotten all the nifty Perl stuff that was in my head..

      Unfortunately, to the last point, if %ENTITIES is a "my" variable in MathML::Entities, you can't access it directly without "breaking the rules"...

      I can't even access it to make a copy, can I? - no way of making %M::E::A::ENTITIES ?

      If I understand it correctly, if %ENTITIES was an "our" variable, I could have added data to it - and the E::M methods would have accessed the now-longer-hash, yes?



      -- Ian Stuart
      A man depriving some poor village, somewhere, of a first-class idiot.
        I can't even access it to make a copy, can I? - no way of making %M::E::A::ENTITIES ?

        Think of a "my" as similar to "private" data in Java (if I remember my Java, that is). It's pretty much totally inaccessable without using XS to violate the encapsulation and troll through the Perl guts directly. Your best bet may be to do a copy/paste into your subclass and modify it that way. Ugly hack and dependency, but probably the sanest alternative if you really need it.

        -xdg

        Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.