Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

How can I inherit from Bit::Vector?

by toma (Vicar)
on Nov 04, 2001 at 23:50 UTC ( [id://123217]=perlquestion: print w/replies, xml ) Need Help??

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

My goal is to add new functionality to Bit::Vector without changing its source code. My strategy has been to make my own class that inherits from Bit::Vector, but it is resisting my strategy.

How can I make inheritance work with Bit::Vector? If inheritance won't work, what approach should I use?

The error message I get is 'Modification of a read-only value attempted' when I try to re-bless the Bit::Vector. If I don't re-bless, I get a Bit::Vector where I expect an LFSR object.

Here is my attempt so far:
The stripped-down calling program:

use strict; use warnings; use diagnostics; use LFSR; my $nbits = 127; my $t = new LFSR($nbits); # Inherited constructor print ref($t),"\n"; # Shows it is a Bit::Vector, not an LFSR # More proof that $t is a Bit::Vector print $t->isa('Bit::Vector'),"\n"; print $t->isa('LFSR'),"\n"; # This line: # bless $t, "LFSR"; # Causes this error: # 'Modification of a read-only value attempted'
The stripped-down module:
package LFSR; use strict; use warnings; use diagnostics; use Bit::Vector; our @ISA = qw(Bit::Vector); # This also causes an error at the bless statement, # so I have it commented out. =pod sub new { my ($class, $nbits)= @_; my $self= new Bit::Vector($nbits); bless $self, $class; return $self; } =cut sub mine { my $self= shift; my $class= ref($self) || $self; print "Hello\n"; } 1;
I am running perl version 5.6.1.

Thanks!
-toma

It should work perfectly the first time! - toma

Replies are listed 'Best First'.
Re: How can I inherit from Bit::Vector?
by Fastolfe (Vicar) on Nov 05, 2001 at 01:48 UTC

    I've researched this a little bit, and I'm not sure that we can work around it. Two things seem to be keeping us from properly inheriting from Bit::Vector:

    1. It doesn't look like you can bless a scalar constant (one marked internally as read-only):

      perl -e '$a = \"constant"; bless($a, "Test");' Modification of a read-only value attempted at -e line 1.

      This is probably normal behavior of Perl (even though I don't understand why), but the problem is that it looks as though Bit::Vector is claiming that its referent is read-only, presumably to prevent you from accidentally modifying its value:

      perl -MBit::Vector -e '$a = new Bit::Vector(8); ${$a} = 2;' Modification of a read-only value attempted at -e line 1.

      This keeps us from re-blessing it into our own class.

    2. The other problem is that Bit::Vector's "new" function is ignoring the first argument to "new", which means it doesn't allow itself to be called in an inherited style. Here's the code in Vector.xs that actually does the blessing:

      reference = sv_bless(sv_2mortal(newRV(handle)), BitVector_Stash);

      This forces the new object to be created in Bit::Vector, ignoring the class passed to the function (it's there in the code, just being ignored).

      I'm no XS expert by any stretch, but this change to Bit::Vector *might* work, which effectively does a stash lookup based on the first argument already passed into the function:

      reference = sv_bless(sv_2mortal(newRV(handle)), gv_stashpv(SvPV_nolen( +class), 1));

      It makes some bad assumptions, though. I'd rather leave this up to the experts to fix properly, if a fix is even desired.

      (update: the above change breaks some of the tests for Bit::Vector, notably the use of $new = $old->new($bits) syntax to create a new Bit::Vector, but your test script does run as you expect.)

    The author of the module is Steffen Beyer <mailto:sb@engelschall.com>. I might shoot him an e-mail to ask him if these behaviors and side-effects are intentional.

      Here's a patch for Bit::Vector that seems to add the proper support for inheritable class names. It breaks 4 tests in the test suite, but they seem to be testing for the ability of the module to not support this, so I'm going to ignore these. All functional tests pass.

      --- Vector.old.xs Sun Nov 4 15:14:40 2001 +++ Vector.xs Sun Nov 4 15:29:51 2001 @@ -257,7 +257,7 @@ { handle = newSViv((IV)address); reference = sv_bless(sv_2mortal(newRV(handle)), - BitVector_Stash); + sv_isobject(class) ? SvSTASH(SvRV(class)) : gv_stashsv( +class, 1)); SvREFCNT_dec(handle); SvREADONLY_on(handle); PUSHs(reference);
      Again, I'd prefer a real solution from the author, but this may work for you in the mean time.
        Thanks for the help!

        Still, it seems that Bit::Vector seems designed not to allow inheritance. Almost all the methods, such as shift_left(), check to see that they are handed a genuine Bit::Vector. If it isn't a Bit::Vector an error is generated.

        I'm beginning to think that I need to use a different strategy. Perhaps I should make an object that has a USES_A rather than an IS_A relationship with Bit:Vector.

        It should work perfectly the first time! - toma

Re: How can I inherit from Bit::Vector?
by alien_life_form (Pilgrim) on Nov 05, 2001 at 06:08 UTC
    Greetings,

    Rather than going through all these hoops, why not just using containment?

    AUTOLOAD makes it very easy to delegate to an inner Bit::Vector everything you do not care to intercept, so the difference from true inheritance is not much.
    Cheers,
    alf


    You can't have everything: where would you put it?

      One should only use inheritance on classes that were designed to be inheritted from. Bit::Vector appears to have not only not been designed to support inheritance, but actually designed to not support inheritance. So I agree that toma should stop fighting it.

      Plus inheritance is a bit of blunt weapon, especially in Perl. Unless you and/or Bit::Vector go out of your way to prevent it, (to take just one example) any non-method utility subroutines must be very carefully named (and Bit::Vector probably doesn't know about your names and so can't avoid accidentally using them in the next release).

      There is even a module on CPAN that makes dispatching the Bit::Vector method calls easy (sorry, I don't recall the name, though).

              - tye (in other words, "me too")
Re: How can I inherit from Bit::Vector?
by alien_life_form (Pilgrim) on Nov 05, 2001 at 21:02 UTC
    Greetings,

    I am posting what follows by toma's request (very nearly yanked from somewhere in the panther bbok, so I cannot really claim authorship :) ).

    package My::Tmain; sub new { #somewhere... $self_>{_TMAIN_}=Win32::OLE->new('mynifty.application') or barf('badly'); #... bless $pkg $self; } #override something sub foo { my $self=shift; my $res = $self->{_TMAIN_}->foo(@_); munge($res); } #elsewhere sub AUTOLOAD { my($self,@args)=(@_); my($cmd); ($cmd=$AUTOLOAD)=~s/.*:://; return if $cmd eq 'DESTROY'; # should not even be called { #this may be bititing toma... no strict 'refs'; # this does the delegation hokey dokey $self->{_TMAIN_}->$cmd(@args); } } #in another file use My::Tmain; my $t= My::Tmain->new(); $t->foo(); # calls the overridden method $t->bar(); # autoloaded
    Note that no strict refs is required to make the ->$cmd( ) bit work. I see nothing that should stop this from working with Bit::Vector... but then again, I would not have anticipated the impossibility to inherit. Manual overriding is obviously possible but much more tedious and error prone than this


    Cheers,
    alf


    You can't have everything: where would you put it?

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (4)
As of 2024-04-19 15:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found