Single-File Inheritance

Discussion in 'Perl Misc' started by Jim Gibson, Jan 18, 2012.

  1. Jim Gibson

    Jim Gibson Guest

    I am trying to do the Right Thing and write a data-processing program
    using lofty Object-Oriented principles, instead of my usual lazy
    procedural ways, but I am having trouble with putting multiple class
    packages into one file. I started out using just one file for
    convenience while I develop a framework, and then was planning on
    splitting the file into separate modules once I got the basics working.

    I am trying to read some data files that have the same format in the
    first 6 lines, then have different data records in subsequent lines. I
    thought I would write a parent class that reads the header lines, then
    child classes to read and parse subsequent lines.

    Here is the result:

    % cat single.pl
    #!/usr/local/bin/perl
    use strict;
    use warnings;

    my $file = ConfigFile->new(); # line 5

    package DataFile;

    sub new
    {
    my($class) = shift;
    my $self = {};
    bless $self, $class;
    return $self;
    }

    package ConfigFile;
    our @ISA = qw( DataFile );


    % perl single.pl
    Can't locate object method "new" via package "ConfigFile" at single.pl
    line 5.


    % perl -v
    This is perl, v5.10.1 (*) built for darwin-2level

    If I put the packages in separate files, it works (compiles and runs).
    I am almost sure that I have done this type of thing before, and I
    can't find any documentation that says I can't.

    Should I be able to put multiple packages in a single file and use
    inheritance for two of those packages?

    Thanks.

    --
    Jim Gibson
     
    Jim Gibson, Jan 18, 2012
    #1
    1. Advertising

  2. Jim Gibson

    Guest

    Jim Gibson <> wrote:
    >
    > % cat single.pl
    > #!/usr/local/bin/perl
    > use strict;
    > use warnings;
    >
    > my $file = ConfigFile->new(); # line 5
    >

    .....
    >
    > package ConfigFile;
    > our @ISA = qw( DataFile );


    > % perl single.pl
    > Can't locate object method "new" via package "ConfigFile" at single.pl
    > line 5.


    The creation of the @ISA alias occurs at compile time (I think), but the
    assignment to @ISA happens only at run time when that line is encountered.

    At the time line 5 is executed, the ISA assignment line has not yet
    be run in the runtime, so has not yet taken place and @ISA is empty.

    You can wrap the @ISA assignment in a BEGIN block to force it to happen at
    compile time, or you can move your main code to be below the package code.

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    The costs of publication of this article were defrayed in part by the
    payment of page charges. This article must therefore be hereby marked
    advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
    this fact.
     
    , Jan 18, 2012
    #2
    1. Advertising

  3. On Tue, 17 Jan 2012 17:08:50 -0800
    Jim Gibson <> wrote:

    > package ConfigFile;
    > our @ISA = qw( DataFile );


    Rather than manually stuff @ISA, I'd use 'parent' with the -norequire
    option:

    package ConfigFile;
    use parent -norequire DataFile;
    ...
     
    David Precious, Jan 18, 2012
    #3
  4. Jim Gibson

    Jim Gibson Guest

    In article <20120117203145.805$>, <>
    wrote:

    > Jim Gibson <> wrote:
    > >
    > > % cat single.pl
    > > #!/usr/local/bin/perl
    > > use strict;
    > > use warnings;
    > >
    > > my $file = ConfigFile->new(); # line 5
    > >

    > ....
    > >
    > > package ConfigFile;
    > > our @ISA = qw( DataFile );

    >
    > > % perl single.pl
    > > Can't locate object method "new" via package "ConfigFile" at single.pl
    > > line 5.

    >
    > The creation of the @ISA alias occurs at compile time (I think), but the
    > assignment to @ISA happens only at run time when that line is encountered.
    >
    > At the time line 5 is executed, the ISA assignment line has not yet
    > be run in the runtime, so has not yet taken place and @ISA is empty.
    >
    > You can wrap the @ISA assignment in a BEGIN block to force it to happen at
    > compile time, or you can move your main code to be below the package code.


    Thanks for the explanation. That works.

    --
    Jim Gibson
     
    Jim Gibson, Jan 18, 2012
    #4
  5. Jim Gibson

    Jim Gibson Guest

    In article <4f16d2bb$5$fuzhry+tra$>, Seymour J.
    <> wrote:

    > In <170120121708505710%>, on 01/17/2012
    > at 05:08 PM, Jim Gibson <> said:
    >
    > >I am trying to do the Right Thing and write a data-processing program
    > >using lofty Object-Oriented principles, instead of my usual lazy
    > >procedural ways,

    >
    > You have to carve the bird at the joints.
    >
    > >I am trying to read some data files that have the same format in the
    > >first 6 lines, then have different data records in subsequent lines.
    > >I thought I would write a parent class that reads the header lines,
    > >then child classes to read and parse subsequent lines.

    >
    > Why? Why not a generic parent class and child classes for header lines
    > and for each category inferred from the header?


    I think that is what I am trying to do. Perhaps I could explain it
    better by saying "write a parent class that has methods to read the
    header lines, and child classes that have specialized methods to read
    and parse subsequent lines." File category is actually derived from the
    file name, not the contents of the header lines.

    >
    > >my $file = ConfigFile->new(); # line 5

    >
    > Shouldn't that be
    >
    > my $file = DataFile->new(); # line 5


    I don't think so. DataFile is the parent class and doesn't have any
    methods to interpret the data. ConfigFile is a child class that reads
    and parses config files (in this simple, made-up example). I won't ever
    instantiate an object of the DataFile class. I will instantiate a
    ConfigFile object and call new() and open() methods on that object,
    which will cause DataFile::new() and DataFile::eek:pen() to be called,
    since ConfigFile inherits new() and open() from DataFile.

    >
    > >If I put the packages in separate files, it works (compiles and
    > >runs).

    >
    > Could yuou show skeletal versions of the individual files?


    The contents of the files are irrelevant for my problem, which happens
    before the files are opened. But thanks.

    --
    Jim Gibson
     
    Jim Gibson, Jan 19, 2012
    #5
  6. Jim Gibson

    Jim Gibson Guest

    In article <20120118193313.3198727a@columbia>, David Precious
    <> wrote:

    > On Tue, 17 Jan 2012 17:08:50 -0800
    > Jim Gibson <> wrote:
    >
    > > package ConfigFile;
    > > our @ISA = qw( DataFile );

    >
    > Rather than manually stuff @ISA, I'd use 'parent' with the -norequire
    > option:
    >
    > package ConfigFile;
    > use parent -norequire DataFile;
    > ...


    Thanks. This works:

    use parent -norequire, 'DataFile';

    although I don't see any advantage over 'our @ISA = ...'

    --
    Jim Gibson
     
    Jim Gibson, Jan 19, 2012
    #6
  7. Jim Gibson

    Jim Gibson Guest

    In article <4f178e61$4$fuzhry+tra$>, Seymour J.
    <> wrote:

    > In <180120121619571440%>, on 01/18/2012
    > at 04:19 PM, Jim Gibson <> said:
    >
    > >I think that is what I am trying to do.

    >
    > No.
    >
    > >Perhaps I could explain it better

    >
    > That's what you wrote the first time; it's not what I'm suggesting.


    OK. Then I guess I don't understand your suggestion.

    > >by saying "write a parent class that has methods to read the
    > >header lines, and child classes that have specialized methods to read
    > >and parse subsequent lines."

    >
    > Why not have the methods for header lines in child classes?


    Because the 6 header lines are the same for all types of files. I have
    written an open() method in the parent class that given the file path,
    opens the file, reads the first 6 lines, and saves the data therein. It
    leaves the file open at the 7th record. The open() method is
    implemented in the parent class and inherited by the child classes.

    What would be the point in duplicating the open method identically in
    all the child classes?

    Thanks for your input. Sorry I don't understand your points.

    --
    Jim Gibson
     
    Jim Gibson, Jan 19, 2012
    #7
  8. Ben Morrow <> writes:
    > Quoth Jim Gibson <>:
    >> <> wrote:
    >> >
    >> > Rather than manually stuff @ISA, I'd use 'parent' with the -norequire
    >> > option:
    >> >
    >> > package ConfigFile;
    >> > use parent -norequire DataFile;
    >> > ...

    >>
    >> Thanks. This works:
    >>
    >> use parent -norequire, 'DataFile';
    >>
    >> although I don't see any advantage over 'our @ISA = ...'

    >
    > It is, by design, equivalent to
    >
    > BEGIN { our @ISA = "DataFile" }
    >
    > and the fact the assignment happens at compile time can be important.
    >
    > For the few circumstances where keeping a class in the 'wrong' file is a
    > good idea, I wouldn't bother with 'parent' and would just use the BEGIN
    > above. 'parent' is useful in the normal case, where you need to load the
    > parent class as well as inherit from it.


    For a lot of not entirely trivial code I have written, this is
    actually the common case and not because classes reside in files which
    won't be found by the search algorithm which happens to be used by
    'use' but because the dependencies among the classes themselves are
    too complex to enabling loading modules defining parent classes from
    the files defining dependent classes. In this case, I usually load all
    modules from the source files containing the main program and declare
    dependencies in the classes themselves.

    Morale: That someone has never seen code where separating loading of
    modules and declaring inheritance relationships was necessary doesn't
    exactly make that someone someone who is qualified to judge that this
    separation doesn't make sense.

    Minor gems:

    {
    no strict 'refs';
    # This is more efficient than push for the new MRO
    # at least until the new MRO is fixed
    @{"$inheritor\::ISA"} = (@{"$inheritor\::ISA"} , @_);
    };

    In plain English, this means 'this is a workaround for a bug in some
    other code' [which isn't used by default]. And this is - of course -
    an atrociously indefficient way to reinvent unshift.

    [rw@sapphire]~ $perldoc -f unshift
    unshift ARRAY,LIST
    Does the opposite of a "shift". Or the opposite of a
    "push", depending on how you look at it. Prepends list to the
    front of the array, and returns the new number of elements in
    the array.


    unshift(@ARGV, '-e') unless $ARGV[0] =~ /^-/;

    Note the LIST is prepended whole, not one element at a
    time, so the prepended elements stay in the same order.
    Use "reverse" to do the reverse.
     
    Rainer Weikusat, Jan 19, 2012
    #8
  9. Rainer Weikusat <> writes:

    [...]

    > {
    > no strict 'refs';
    > # This is more efficient than push for the new MRO
    > # at least until the new MRO is fixed
    > @{"$inheritor\::ISA"} = (@{"$inheritor\::ISA"} , @_);
    > };
    >
    > In plain English, this means 'this is a workaround for a bug in some
    > other code' [which isn't used by default]. And this is - of course -
    > an atrociously indefficient way to reinvent unshift.


    It isn't unshift at all, of course, I just mistakenly assumed that it
    had to be doing something other than adding elements to the end of a
    list ...
     
    Rainer Weikusat, Jan 19, 2012
    #9
  10. Rainer Weikusat <> writes:
    > Ben Morrow <> writes:


    [...]

    >> For the few circumstances where keeping a class in the 'wrong' file is a
    >> good idea,


    Here's what the Camel book has to say on "using WRONG files" (NB: A
    copy of that resides on my bookshelf at home some please spare me the
    anti-scientific outcry this time):

    Sometimes folks are surprised that including a class in @ISA
    doesn't require the appropriate module for you. That's because
    Perl's class system is largely orthogonal to its module
    system. One file can hold many classes (since they're just
    packages), and one package may be mentioned in many files.

    But I guess that has also been 'deprecated' by someone meanwhile ...
     
    Rainer Weikusat, Jan 19, 2012
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Randall Parker
    Replies:
    1
    Views:
    609
    S. Justin Gengo
    Dec 12, 2005
  2. Chris
    Replies:
    1
    Views:
    13,661
    Oisin
    Mar 24, 2006
  3. chris brat
    Replies:
    1
    Views:
    645
    chris brat
    May 10, 2006
  4. Eric Layman
    Replies:
    3
    Views:
    636
    Rad [Visual C# MVP]
    Apr 14, 2007
  5. goodfella

    single producer, single consumer

    goodfella, Oct 6, 2009, in forum: C++
    Replies:
    41
    Views:
    1,935
    James Kanze
    Oct 12, 2009
Loading...

Share This Page