OO Perl Online Learning

  • Thread starter Xiong Changnian
  • Start date
X

Xiong Changnian

I've browsed my fingers off, read all the obvious sources and quite a
few that are off-topic for my needs. I've even been to the local
computer bookstore; there are many books on OO Perl, each with a hefty
price tag. I'm not cheap; I'm broke.

There seems to be little online between perltoot and the like; and
highly specific discussions that assume advanced knowledge and dive into
esoterics. I don't see the bridge -- general intermediate discussion of
OO Perl.

Here are the kinds of questions I've been trying to answer for myself:

* What is all this about makefiles and installation? Why isn't it enough
to download a module and un-tar it to my lib directory? Perhaps I'm
handicapped, running MacPerl under OS 9. I haven't been able to install
anything I've downloaded, not even stuff that shouldn't have anything to
do with the Mac file system.

* All the CPAN modules seem to be just one class per module; every
source I've read says you *can* declare more than one package in a file
but it seems that in practice, it's one class, one package, one module,
one file. Yet I'm contemplating a set of perhaps 20 closely related
classes. I don't know if I'm taking the wrong approach or if there's a
way to bundle them neatly. And yes, I've read a little on CPAN bundles;
I'm still in the dark. I suspect this question ties into the last.

* The *use* pragma makes a class available in a given file but doesn't
seem to propagate; I have to *use* the class everywhere I, well, use it.
Is there no single place I can declare an entire set of classes for use
in any script that *uses* that file? This obviously ties into the last.

* Same question, different angle: If I *use* and inherit among a group
of classes, it seems I run into dependency problems. Is this a lack of
clear thinking on my part and I need to draw up a strict table of
dependencies and work out the order in which the compiler sees
declarations? Or can I just throw everything in if I declare them the
"right" way?

* What's all this about test suites? I can understand writing a script
that stands on its own and exercises a module. I see discussions that
look as though these test scripts are being generated automatically in
some way.

* Should I *always* use strict and use warn? I've been doing just that,
beating the code until it works under these conditions. I see a lot of
code online that shouldn't, though. Right now, I'm using symbolic refs
in one place and I feel I oughtn't.

Nobody has to take the time to answer any of these questions *here* but
I'd love a pointer or five.

Xiong
 
S

Scott Bryce

Xiong said:
I've browsed my fingers off, read all the obvious sources and quite a
few that are off-topic for my needs. I've even been to the local
computer bookstore; there are many books on OO Perl, each with a hefty
price tag. I'm not cheap; I'm broke.

The public library is your friend. My local library has a copy of
Damian Conway's Object Oriented Perl.
 
C

Charlton Wilbur

XC> * What is all this about makefiles and installation? Why isn't
XC> it enough to download a module and un-tar it to my lib
XC> directory? Perhaps I'm handicapped, running MacPerl under OS
XC> 9. I haven't been able to install anything I've downloaded,
XC> not even stuff that shouldn't have anything to do with the Mac
XC> file system.

First off, you are indeed handicapped by running MacPerl under OS 9.

It isn't enough to simply download a module and un-tar it because a
number of other files may need to be changed. The module installation
process also includes ensuring the module is as packaged, that all
prerequisites are in place, and that all necessary files (such as
those used to generate perldoc perllocal) are updated. Some modules
also have stubs to link to C libraries, which require a C compiler.
Because Perl was conceived on Unix, the most obvious way to manage all
this was with Makefiles.

On platforms that don't include compilers and Makefiles, alternative
approaches have been developed, from BSD ports and packages to
ActiveState Perl package repositories. Unfortunately for you, OS 9 is
neither Unixlike nor actively supported, which means you're out of luck.

If you insist on not upgrading to OS X, you might consider getting an
external drive and installing one of the PPC Linuxes on it. If you
insist on remaining on OS 9, you need to prepare yourself for a lot of
frustration and annoyance.

XC> * What's all this about test suites? I can understand writing
XC> a script that stands on its own and exercises a module. I see
XC> discussions that look as though these test scripts are being
XC> generated automatically in some way.

They aren't necessarily generated automatically, but if you conform
with the behavior expected by Test::Simple and its relatives, you can
run them automatically during development and run them automatically
at installation time.

XC> * Should I *always* use strict and use warn? I've been doing
XC> just that, beating the code until it works under these
XC> conditions. I see a lot of code online that shouldn't,
XC> though. Right now, I'm using symbolic refs in one place and I
XC> feel I oughtn't.

Yes, you should *always* use strictures and warnings, especially as
they're both scoped, and when you need to do something that violates a
stricture or warning, you can turn that diagnostic off in the smallest
possible scope. Even then, there's almost always a better way.

XC> Nobody has to take the time to answer any of these questions
XC> *here* but I'd love a pointer or five.

As to your questions about OO syntax and inheritance --
_Object-Oriented Perl_, by Damian Conway. Good luck.

Charlton
 
J

John Bokma

Xiong Changnian said:
* All the CPAN modules seem to be just one class per module;

I can confirm that this is /not/ true. Just grep for package over all pm
files and I am sure you will find modules already installed that have more
then one class per pm file.
one file. Yet I'm contemplating a set of perhaps 20 closely related
classes.

Unless they are very short (linewise) you might be better of to put each
in a file of their own. Or a combination. 20 classes in one file is IMO a
pain in the ass to edit, even if you can split your window in 2 or more
views.
* Should I *always* use strict and use warn? I've been doing just that,
beating the code until it works under these conditions. I see a lot of
code online that shouldn't, though. Right now, I'm using symbolic refs
in one place and I feel I oughtn't.

Show the code. The nice thing of use warnings is that you can disable
warnings for a block.
 
X

xhoster

Xiong Changnian said:
I've browsed my fingers off, read all the obvious sources and quite a
few that are off-topic for my needs. I've even been to the local
computer bookstore; there are many books on OO Perl, each with a hefty
price tag. I'm not cheap; I'm broke.

There seems to be little online between perltoot and the like;

By "the like", do you mean perlobj, perlboot, perltooc, perlmod and
perlbot?
and
highly specific discussions that assume advanced knowledge and dive into
esoterics. I don't see the bridge -- general intermediate discussion of
OO Perl.

Here are the kinds of questions I've been trying to answer for myself:

* What is all this about makefiles and installation? Why isn't it enough
to download a module and un-tar it to my lib directory?

Usually it is. If it isn't, it could be that the module is not pure Perl
but has XS code that needs to be compiled, or it is dependent on other
modules which you don't have installed.

* All the CPAN modules seem to be just one class per module;

Look at more modules. Tie::File, for example, has two helper classes.
And that is not unusual. Running:

egrep -rc '^package' $PERL5LIB | awk -F: '$2>1 {print $1}'

Should point out some more candidates for having more than one class per
file.
every
source I've read says you *can* declare more than one package in a file
but it seems that in practice, it's one class, one package, one module,
one file. Yet I'm contemplating a set of perhaps 20 closely related
classes. I don't know if I'm taking the wrong approach or if there's a
way to bundle them neatly.

You just put all the code in one file with multiple package statements.
Unless you need to import stuff, there should be no problem.

* The *use* pragma makes a class available in a given file but doesn't
seem to propagate;

Could you give an example? I've not had this problem with OO modules.

Xho
 
P

Peter J. Holzer

* What is all this about makefiles and installation? Why isn't it enough
to download a module and un-tar it to my lib directory?

If it's a pure perl module, that will work. However, as Charlton already
mentioned, some modules are not pure perl, and the installation process
also checks dependencies and does some bookkeeping.

There is another important point: Testing.

By downloading the module into one directory and then installing it you
can test a module before you install it (and possibly overwrite a
working version with a non-working version). Most Modules on CPAN come
with a test-suite. If you run "make test" before "make install" (cpan
will do that automatically), you can be reasonably sure that the module
will work as expected on your system (which is even more important if
you run a relatively exotic system like MacOS 9 - you do need a "make"
command, though. Only a few distributions use Module::Build instead of
Makemaker).


* All the CPAN modules seem to be just one class per module;

Nope. There are quite a few which have more than one class/package per
file.
every source I've read says you *can* declare more than one package in
a file but it seems that in practice, it's one class, one package, one
module, one file.

Putting several packages into a single file is generally less clear, and
you can't "use" a package if the filename can't be derived from the
package name - so all your "public" packages must be in a file of their
own. "Private" packages which aren't supposed to be "use"d by the
programmer are sometimes put into the same file as the package which
uses them.
Yet I'm contemplating a set of perhaps 20 closely related classes. I
don't know if I'm taking the wrong approach or if there's a way to
bundle them neatly. And yes, I've read a little on CPAN bundles;

No need to bundle them. If they are closely related, put them into the
same distribution.

* The *use* pragma makes a class available in a given file but doesn't
seem to propagate; I have to *use* the class everywhere I, well, use it.

Not quite. You only need to "use" the class where you need to import
its symbols, and obviously you need to load the module to use any code
in it, so you need to "use" (or require, do, whatever) it somewhere.

But you can use objects of classes and even class methods of packages
which you didn't use directly. For example, in

use MIME::parser;

my $parser = new MIME::parser();
my $entity = $parser->parse(\*STDIN);
my $head = $entity->head();

$entity is an object of the class MIME::Entity, and $head is a
MIME::Head. You don't need to "use" these modules to use these objects.
MIME::parser "use"s them, and that's sufficient.

* Same question, different angle: If I *use* and inherit among a group
of classes, it seems I run into dependency problems. Is this a lack of
clear thinking on my part and I need to draw up a strict table of
dependencies and work out the order in which the compiler sees
declarations? Or can I just throw everything in if I declare them the
"right" way?

Inheritance is a bit of a sore spot in perl. It depends on how the
classes you want to inherit from are written.

* What's all this about test suites?

They help you find bugs.
I can understand writing a script that stands on its own and exercises
a module.

A test suite is a collection of such scripts.
I see discussions that look as though these test scripts are being
generated automatically in some way.

No, they aren't (normally) *generated* automatically. You need to write
them yourself, and that often takes as much thought as writing the
actual code (unless your specification is already very detailed and
formal, in that (rare) case, a test-suite can be genereted from the spec
(semi-)automatically). However, the test suite is *run* every time you
type "make test" and every time someone installs the distribution via
CPAN. So errors which are covered by a test-case will be found soon.

hp
 
X

Xiong Changnian

Charlton Wilbur said:
If you insist on not upgrading to OS X, you might consider getting an
external drive and installing one of the PPC Linuxes on it. If you
insist on remaining on OS 9, you need to prepare yourself for a lot of
frustration and annoyance.

It's difficult to explain why I still run OS 9 and I'm not sure this is
the place for it. Assume all the reasons given by bad managers for
legacy systems and stir in a large helping of poverty. Fact is, I've got
my beige G3 hot-rodded, hardware and software, to an impressive extent.
It works -- most of the time -- very well.

I tried, over a period of about six months, to install various flavors
of Linux on a beige Mac. It was a nightmare. I think the way out of my
corner is to wait until I have enough workspace to set up two
workstations, buy a cheap Intel box and put a standard Linux distro on
it -- never touch windoz -- and go back and forth between the two
systems until I make the transition. Even then, I anticipate a PowerBook
for years to come. There is simply no reasonable way, in some cases, to
convert old work files.
if you conform
with the behavior expected by Test::Simple...

I have plain Test installed and I looked over the POD before I posted
here. It assumes I already know what the author is driving at. I'll
exercise it a bit and see what happens. I'm afraid I'm not really an
experimentalist at heart; I like to read the manual. I've been looking
at a number of files shipped with MacPerl with the extension .t as well.
I suspect I will learn something.


Scott Bryce said:
The public library is your friend. My local library has a copy of
Damian Conway's Object Oriented Perl.

I should have thought of that. This *is* San Jose. Even $21.50 for the
PDF is too rich for my blood.


John Bokma said:
Just grep for package over all pm
files and I am sure you will find modules already installed that have more
then one class per pm file.

I've been looking for such examples; I'll look harder.
Unless they are very short (linewise) you might be better of to put each
in a file of their own. Or a combination. 20 classes in one file is IMO a
pain in the ass to edit, even if you can split your window in 2 or more
views.

You're right, of course. But 20 files is also a kind of pain. I think a
balanced hierarchy would be something like 5 distinct files, one each
for important, complex classes; plus another 2 or 3 files containing
these itty-bitty classes that have only perhaps 2 methods each.
Show the code. The nice thing of use warnings is that you can disable
warnings for a block.

I posted that before. Here again:

sub report_sets {
my @keys = sort keys %{ $ref->{SETS} };
foreach (@keys) {
&{"report_" . lc($_)} ($ref->{SETS}{$_})
or die ("No report subroutine for $_.");
};
};

Many such subs, one for each hash key; some actually do something.
Symbolic ref, so I bracket this with no strict "refs";

It *does* work but I'm pretty sure there *is* a better way; I just have
to make every hash level an object -- which leads to a proliferation of
"internal" classes, most obviously named after the hash keys which
invoke them. Thus my worries about -- "bundle bloat"?


By "the like", do you mean perlobj, perlboot, perltooc, perlmod and
perlbot?

Yes, Sir, I believe I've read them all three to seven times. They're
pretty basic. There may still be stuff to be gleaned from them but I
look forward to paging through Conway.
Look at more modules. Tie::File, for example, has two helper classes.
And that is not unusual.

I don't have Tie::File handy but I'm just now looking over Tie::Array,
which has in the file both package Tie::Array and package Tie::StdArray;
and I will study this until I see how it works. Good tip.
Could you give an example?

I'd better put a lengthy code example in another post. First, I want to
strip out all possible dead wood. Thanks for the invitation.

And many thanks to all for the extensive help.

Xiong
 
C

Charlton Wilbur

XC> In article <[email protected]>,

XC> It's difficult to explain why I still run OS 9 and I'm not
XC> sure this is the place for it.

It doesn't matter, and it isn't. What I said, I stand by; the fact
that you have very good reasons to remain on OS 9 will not alter the
frustration and annoyance.

Charlton
 
U

Uri Guttman

XC> In article <[email protected]>,

XC> I should have thought of that. This *is* San Jose. Even $21.50 for the
XC> PDF is too rich for my blood.

it is old enough that there are many used copies out there. check amazon
and ebay for copies.

also beginning perl is online and free at learn.perl.org. i don't how
deep it gets into OO but it may help some

XC> In article <[email protected]>,

XC> I've been looking for such examples; I'll look harder.

XC> You're right, of course. But 20 files is also a kind of pain. I think a
XC> balanced hierarchy would be something like 5 distinct files, one each
XC> for important, complex classes; plus another 2 or 3 files containing
XC> these itty-bitty classes that have only perhaps 2 methods each.

i think 20 related classes means you are over classifying things. that
is the java and not the perl way. do they really need to be separate
classes? are they all variants of each other or a parent class? are you
reusing them in different places or only all at once? whenever i see too
many of anything in one place i suspect a design flaw.

XC> I posted that before. Here again:

XC> sub report_sets {
XC> my @keys = sort keys %{ $ref->{SETS} };
XC> foreach (@keys) {

use named variable when possible. it makes for more easily understood
code.

XC> &{"report_" . lc($_)} ($ref->{SETS}{$_})

eww, that is symrefs. make a dispatch table and your code will be
cleaner and safer. google this group for 'dispatch table' and you will
find many threads on it.


XC> or die ("No report subroutine for $_.");
you can't die that late. you already called the unknown sub. a dispatch
table will allow a check before calling which is what you want.

XC> };
XC> };

XC> Many such subs, one for each hash key; some actually do something.
XC> Symbolic ref, so I bracket this with no strict "refs";

bad boy! no cookie for you. dispatch tables are the best way to do that
and no symrefs are needed.

XC> It *does* work but I'm pretty sure there *is* a better way; I just have
XC> to make every hash level an object -- which leads to a proliferation of
XC> "internal" classes, most obviously named after the hash keys which
XC> invoke them. Thus my worries about -- "bundle bloat"?

you don't have to make every hash level an object. that is again the
java way and i doubt you need to do that here. too many objects is just
as bad as too few. objects are meant to help organized code and data,
not tag them to death like xml.

XC> Yes, Sir, I believe I've read them all three to seven times. They're
XC> pretty basic. There may still be stuff to be gleaned from them but I
XC> look forward to paging through Conway.

you need an eighth reading! :) OOP is a great book and you should beg
borrow or (well not really) steal a copy. used copies are your best bet
as i have said.

XC> I'd better put a lengthy code example in another post. First, I want to
XC> strip out all possible dead wood. Thanks for the invitation.

use does two things and you seem to be confusing them. one is to load a
module and that needs to be done only once (basically the same as
require but which loads at runtime). the other is to call the import
mathod of the class you loaded and that needs to be done in each file
that wants exported symbols. but if you are doing only OO in a module
and not exporting anything then it can be loaded once with use. again, i
suspect you are creating too many classes and may be crossing OO with
exported symbols which is not a good idea.

when you post more code it will be easier to help with the bigger design
issues i sense here. i smell an XY problem which means you picked a
solution X and are working hard but you really need solution Y.

uri
 
X

Xiong Changnian

Okay, thanks for help given -- the most helpful thing was the naked
assertion that multiple classes *may* be coded into a single file. I now
have my test case working.

My problem seems not to have anything to do with Mac filesystem but it
may. The issue is that I lost heart when I could not seem to get methods
recognized even though I had these nice use and base declarations in
each file.

For the following, I've translated folders into *nix directory
conventions.

The .pl testbed itself is in /usr/; there is a subdir /usr/Jam/ which
contains, in Band.pm, the putative "important" class and, in Guts.pm,
three "helper" or "internal" classes.

It seems that I must use Jam::Band; I can't use Band. On the other hand,
I must use base qw(Band) and not use base qw(Jam::Band). You'll forgive
me if I find this inconsistent. I'm sure there's a good reason; I just
don't see it.

I've always put the package declaration first, ahead of use statements;
it seems logical that if I'm declaring multiple packages, I may as well
put the use statements before the first package. I feel it might be best
to keep the package first, though, in single-class files.

I'm still not sure if I *must* use base for each class, so long as they
all inherit from the same branch. This should, I suspect, always be the
case; let there be another file for classes that inherit from another
branch but group the tiny helper classes that are all "siblings" in one
file. This is something I can thrash out by experiment.

Again, thanks for the prods. I beat on this for hours with no success
but it all started to work when I began to believe it could be done.

Xiong


### /usr/jamsession.pl ###

use strict;
use warnings;
use Jam::Band;
....
my $one = new Band;
$one->add('Tuba','whonk');
$one->play('Tuba');
....

### /usr/Jam/Band.pm ###

package Band;
use strict;
use warnings;
use Jam::Guts;

sub new {
....
};

sub add {
...
my $instrument = new $kind;
$instrument->tune($sound);
$obj->{$kind} = $instrument;
};
....
....

### /usr/Jam/Guts.pm ###

use strict;
use warnings;
use Jam::Band;

package Tuba;
use base qw(Band);

sub tune {
....
};

package Drum;
use base qw(Band);

sub tune {
....
};
....
....

######
 
X

xhoster

Xiong Changnian said:
The .pl testbed itself is in /usr/; there is a subdir /usr/Jam/ which
contains, in Band.pm, the putative "important" class and, in Guts.pm,
three "helper" or "internal" classes.

It seems that I must use Jam::Band; I can't use Band.

You could use Band as long as /usr/Jam was in the perl lib path, or if you
run the script with a cwd of /usr/Jam. If neither of these is the case,
then you need the Jam:: or else perl doesn't know to look for Band in the
Jam directory. Presumably you only want /usr in your perl lib path, and
you want this to refered to as Jam::Band, right?
On the other hand,
I must use base qw(Band) and not use base qw(Jam::Band). You'll forgive
me if I find this inconsistent. I'm sure there's a good reason; I just
don't see it.

See the next item below.

....
### /usr/Jam/Band.pm ###

package Band;

If you want to refer to this as Jam::Band in other classes "use base"
lines, then the "package" statement would need to declare it as such:

package Jam::Band;


Xho
 
X

Xiong Changnian

Uh, thanks to Xho for explaining why I use Jam::Band but use base Band
when I package Band. Sorry if I'm stubborn and cranky but well, I still
find it inconsistent.

But if I can use Jam::Band and use base Jam::Band if I package
Jam::Band, then I will sleep better. Thanks.


Uri Guttman said:
i think 20 related classes means you are over classifying things. that
is the java and not the perl way. do they really need to be separate
classes? are they all variants of each other or a parent class? are you
reusing them in different places or only all at once? whenever i see too
many of anything in one place i suspect a design flaw.

Ah, I covered my application in too much detail in an earlier thread;
I'd better not repeat myself. Yes; yes they are all related but although
they can reasonably inherit a few methods, some will be distinctly
different; they will be used in a wide variety of configurations; and I
agree.

The nub of it is that some objects (classes, but bear with me) logically
include others, just as Dinner includes Entree and Desert. This makes
sense to the user of the -- Restaurant *thing* (Not a module, not a
bundle, the whole folder full of related stuff = project?). Meanwhile,
it seems that most of these objects have similar structures. For
instance, every one of my logical objects has a first-level SELF key,
pointing to a small hash with keys like NAME and COLOR. Other
first-level keys may point to sets of objects or arrays of data.

The point being that since each of these objects has a SELF key/hash
containing similar data, it makes sense to me to build a Self object and
write general methods to handle it. Self has no "external" meaning to
the outermost, using script; perhaps I should call it _Self. There are
already a couple cases like this and by the time the entire *thing* is
written, I expect about 10 logical objects and perhaps another 10
internal helper objects. What I'm doing, without going into too much
detail, really does involve a lot of distinct classes of things --
things that behave in fundamentally different ways, not just dozens of
instances of the same class.

I agree that my current method, in which I tried to limit myself to
logically sensible objects and went bashing around with symbolic refs,
is ugly and Bad. That's why I posted here: I was happy I got it to work
and immediately looked for a better solution.

Now, I've got that silly example working and I'm (momentarily) content.
One top class in its own file with new() and other general cross-project
methods; one file each for the big, external classes; one helper file
for all the small _internal classes; and all inherit from the top.

I really can't thank you guys enough.
use named variable when possible.
it makes for more easily understood code.

Sorry, I haven't the faintest idea what you're driving at, unless you're
already talking about the symref -- and that comes in the next line.
Maybe you just want me to deref to a temp variable before proceeding.
I'm content to jam it all in one line.

I'm from the days when absolutely everything had to be declared and
reserved; every single operation was one instruction at a time.
Sometimes one machine-language instruction actually ran to more than one
line of code.

I'd spend a week writing the equate table before typing the first line
of executable -- and that would be at address 0, and I knew it was at 0,
and I knew it had to be the system boot because when the power came on,
the processor would start at 0, god willin ana river doan rise. If I
wanted to loop, I had to declare and maintain the whole structure and
no, I didn't trust the assembler to put things where I wanted. I'd
assemble and dump it onto 132-col greenbar and check the hex. Up to me
which register to use for the count and all my fault if I picked wrong.
Sometimes I patched shipping firmware directly in hex -- code, not
constants. I don't do that anymore.

When I iterate over an array without knowing, anywhere, the loop
iterator even exists I get a little woody. :p You see the verbose
version of my code. Yes, I know, it's a sin. Sorry.
XC> &{"report_" . lc($_)} ($ref->{SETS}{$_})
...make a dispatch table...

Oooh, sorry, but I sort of disagree. Maybe better than blatantly
constructing the sub name out of sticks and pebbles on the fly but a
jump table is a jump table, no matter what you call it. I'm looking for
more elegance.

Please relax; I have no intention of really using what I call a
"calculated jump". As I posted, that's the first thing to break. Last
time I tried that for a client on a serious project, was 20 years ago
and I thought I was cool. I only did it because it could be done -- and
because nobody had ever educated me as to why it might be risky.

Also, please breathe easy about the multiple objects. I'm off the clock
on this; it's a personal project. I can afford to go in the wrong
direction for a long time, learn something while I'm there, and
mercilessly refactor until the chrome gleams.

Still, thank you for your concerns.

Xiong
 
X

Xiong Changnian

A. Sinan Unur said:
You are sounding cranky and stubborn...

I'm really very sorry if it appears that way to you. I *am* a cranky,
stubborn old man but I try not to act that way in every circumstance.

If I qualify the module with Jam::Band in package, use, and use base, it
works. I didn't see why, *instead*, as I've been doing, I can sometimes
call it merely Band.

My explanation is that use refers to the file itself, so needs the
directory relative to my script; use base and package refer to the
package/class instead and require no such qualification.

It makes sense, then, that I was able to declare packages/classes Tuba,
Drum, and Violin all in the file Guts.pm. I use Jam::Guts because there
is no file Jam::Tuba. I might (somewhere) use base qw(Tuba Drum Violin)
if for some mad reason, I want to inherit Moog from all three mommies.

If this isn't so, no matter; the vehicle takes me where I want to go and
my elbow is comfortably removed from the big red button. I'm entirely
satisfied with the answers I was given.

Thanks again for the suggestions.
 
U

Uri Guttman

XC> But if I can use Jam::Band and use base Jam::Band if I package
XC> Jam::Band, then I will sleep better. Thanks.

XC> In article <[email protected]>,

XC> Sorry, I haven't the faintest idea what you're driving at, unless you're
XC> already talking about the symref -- and that comes in the next line.
XC> Maybe you just want me to deref to a temp variable before proceeding.
XC> I'm content to jam it all in one line.

you used a for loop with the implied use of $_ as the loop variable. it
is better to use a named lexical variable instead like this:

for my $foo ( @bars ) {

it makes the code easier to understand since the loop body will have
that name to help document it. i only use $_ in map/grep where it is
required and in special cases where it works better.

XC> I'm from the days when absolutely everything had to be declared and
XC> reserved; every single operation was one instruction at a time.
XC> Sometimes one machine-language instruction actually ran to more than one
XC> line of code.

you don't have to tell us your background regarding declarations. most
of the regulars here know multiple langs and know all about this area.


XC> When I iterate over an array without knowing, anywhere, the loop
XC> iterator even exists I get a little woody. :p You see the verbose
XC> version of my code. Yes, I know, it's a sin. Sorry.

but you didn't use an explicit loop iterator variable but the default
$_.

XC> &{"report_" . lc($_)} ($ref->{SETS}{$_})

XC> Oooh, sorry, but I sort of disagree. Maybe better than blatantly
XC> constructing the sub name out of sticks and pebbles on the fly but a
XC> jump table is a jump table, no matter what you call it. I'm looking for
XC> more elegance.

XC> "calculated jump". As I posted, that's the first thing to break. Last
XC> time I tried that for a client on a serious project, was 20 years ago
XC> and I thought I was cool. I only did it because it could be done -- and
XC> because nobody had ever educated me as to why it might be risky.

this is very wrong in several ways. it is a symref which you said you
don't want to do and no one recommends that you do. it is not testing if
the sub exists or not. it is a potential source of future bugs (all
synrefs are). it uses the symbol table as a general purpose hash when it
should be only used to mung the symbols. you can make the dispatch table
a lexical hash whics is safer (more private) and you can pass it around
or store it in something else like an object (can't be done with symrefs
since they are global). so there are many reasons to use a dispatch
table and none that support using symrefs there. you asked for advice on
coding and this is one answer you shouldn't ignore regardless of your
taste and style. it is BAD coding to use symrefs if there is a better
way to do it. that is why use strict disallows them.

uri
 
U

Uri Guttman

XC> In article <[email protected]>,

XC> I'm really very sorry if it appears that way to you. I *am* a cranky,
XC> stubborn old man but I try not to act that way in every circumstance.

XC> If I qualify the module with Jam::Band in package, use, and use base, it
XC> works. I didn't see why, *instead*, as I've been doing, I can sometimes
XC> call it merely Band.

XC> My explanation is that use refers to the file itself, so needs the
XC> directory relative to my script; use base and package refer to the
XC> package/class instead and require no such qualification.

you don't understand use, package names and modules yet. i will try to
explain them better. first off, the argument to use, a package name and
a module name/path are officially unrelated. you can use any value in
any of those places if you know what you are doing. there are ways they
are related and with conventions too and if you take advantage of them
they work well together.

package command name is just the default symbol table space for all the
code that follows it until the next package command or the end of the
file/eval block. this means you can put the same package name in
multiple modules and multiple package names in one module. a package
command has no other purpose but to set the default name for unqualified
globals. if you fully qualify all globals in use you would never need a
package command.

a module name (really just a file name) is just that, the name of a
physical module or file. it has nothing official to do with its contents
or any package names inside the file. the module name is just used to
locate and load a particular source file with a .pm suffix (i am
ignoring .so and related c libs here). if a module name is in some
subdirs like Foo/Bar/Util.pm those directories are not part of the
file name but need to be used to find the module.

a require command will take a class name Foo::Bar::Util and break up the
:: parts and convert the names into file system specific dirs, searches
OINC for it, opens that file (it adds a .pm suffix) if found and loads
it into perl. this is done at runtime and no symbol table munging
(exporting) is done for you. the module itself can do what it wants in
mainline code which will run then. require is executed at runtime so it
is good for loading modules on demand but not for loading symbols you
need in the current code.

a use command is a combination of a require and a call to the import
method. here is where things get interesting with module names and
package names. use does the same lookup of the file as require (note
that this can be case insensitive on some file systems which is a
classic newbie bug) and loads the file. but then it will take the class
name it was passed and call the class method import and pass it any
other args on the use line. in the common OO case, no import is found
since you don't export methods or symbols in pure OO. in typical
procedural modules some form of Exporter (there are a few now) will be
inherited and have an import method which gets called. it locates the
@EXPORT/_OK and related variables in your package and exports symbols
into the package with the use line as requested. note that it calls
import on ONLY one name, the class name passed to use. if you have more
than one package name in a module and one of them is the same class name
as called by use, only that package's import (usually inherited as i
said but it can be an explicit sub) is called. this is where some get
confused about multiple package names in a module and things not being
exported as expected.

finally we come to use base. base.pm is a simple pragma that saves a
little work when using inherited classes. it does two things, it loads
the requested module (but not with use which is fine as this is meant
for pure OO modules) and it also unshifts the classname into the current
package's @ISA (which controls method lookups for inheritance). so the
module name and class name when you do use base must agree if you want
the proper file to be loaded and to properly inherit from it. you can't
just pick names that seem right and do use base and it will work. your
case seems to be like that, you didn't make sure the module path and the
class names agreed when you did use base. in your case with all those
classes in one file and they all inherit from the same set, it would be
cleaner to just to a use at the top of the file and do this inside each
package:

# top of file and one time only. loads the file once which is all that
# is needed.

use Parent::Classes ;


# do this for each package in the file as needed
# doesn't load any files but sets up inheritance any way you want.
# note that the parent name isn't the same as the file loaded as i
# wanted to show how they can be different

package My::Foo ;

BEGIN{ our @ISA ; unshift 'Parent::Class::Foo, @ISA }

note that the use line can specify ANY module it wants and you can then
inherit separately in each class in the file. use base won't allow this
separation but it is designed for the common case where the package
names and files agree.

XC> It makes sense, then, that I was able to declare packages/classes
XC> Tuba, Drum, and Violin all in the file Guts.pm. I use Jam::Guts
XC> because there is no file Jam::Tuba. I might (somewhere) use base
XC> qw(Tuba Drum Violin) if for some mad reason, I want to inherit
XC> Moog from all three mommies.

i don't exactly get that but i think you should understand my explanation
above. you need to understand how these names and calls relate to each
other and not guess and thrash about.

uri
 
U

Uri Guttman

MD> Oh c'mon! This is just *so* controversial... even slightly
MD> flame-baiting... I use $_ all the time in loops, provided they're
MD> short enough. If possible I cast them in a statement modifier form,
MD> even. If code is self explanatory it is... err, well, self
MD> explanatory. Of course I would never recommend to use $_ with a for
MD> loop having a main block of 25 lines!!

i wouldn't call it controversial or flame baiting. you can disagree with
it but most style guides (PBP included) recommend named variables
whenever possible. sure it is a style issue but i am a strong advocate
of named variables as part of an overall style. and i emphasize choosing
quality names which makes it work even better.

XC> "calculated jump". As I posted, that's the first thing to break. Last
XC> time I tried that for a client on a serious project, was 20 years ago
XC> and I thought I was cool. I only did it because it could be done -- and
XC> because nobody had ever educated me as to why it might be risky.MD> [snip]

MD> I wholeheartedly agree with you, but some details, including the
MD> "calculated jump" one above make me suspect that the OP really
MD> misunderstood the meaning of "dispatch table", in which case I renew
MD> the invite for him to look it up.

well, i took calculated jump as the symref since that is a calculated
name of the sub to call. but later the OP seemed to agree with me so i
am confused as to whether he is going to use a dispatch table.

uri
 
U

Uri Guttman

MD> Well, PBP (and Perl::Critic) is somewhat controversial too. Some
MD> knowledgeable and respectful Perl hackers beg to differ on some
MD> specific points.

i was one of the tech editors of PBP and i disagree with many
points. but i do agree on using names vars where possible (some
exceptions do apply). damian explicitly states that PBP is meant to be a
possible set of rules and not an absolute set. you can pick and choose
and make up your own but consistancy in style is the goal, not a
particular style. and you should have at least a reason why any style
point is chosen and not some random default reason. good style has logic
behind it that defends it. i say named vars make the code more
readable as names help document what is being worked upon vs $_ which
has no such benefit. $_ can be set far enough away as to make it harder
to track its meaning. it can also cause action at a distance as it is a
global (though it can be localized by for or explicitly). just having
named vars be lexicals is a win too.

uri
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top