Re: max/min

2002-04-12 Thread Richard J. Barbalace

Jonathan Paton writes:
>> After I sent this I had a flash of enlightenment:
>>$max = (sort {$a <=> $b} @_)[-1];
>> May be slower, though, I don't know.
>
> How many times have I seen this?  I mean, I've seen
> this construct many times, and the question deserves
> a place in the Perl FAQ.

How to find the min/max value of an array is certainly a FAQ, so it
should be put in the official Perl FAQ.  How does someone recommend
this?

I couldn't find the benchmark discussion from a few months ago, so
I tested the various suggestions already mentioned on the list.  I
used the following max functions:

sub max1 {
(sort {$a <=> $b} @_)[-1];   # sort
}
sub max2 {
my $max = shift;
foreach (@_) { $max = $_ if $_ > $max }  # if modifier
return $max;
}
sub max3 {
my $max = shift;
map { $max = $_ if ($_ > $max) } @_; # map in void context
return $max;
}
sub max4 {
my $max = shift;
foreach (@_) { $max = $_ > $max ? $_ : $max; }   # ternary operator
return $max;
}

I benchmarked these against arrays containing 10, 100, 1000, and 10k
elements.  The results should not be surprising to those who have been
following the discussion.  I also tested equivalent min functions with
nearly identical results.  The actually results will vary depending on
your hardware and software configuration, but these difference should
be typical.

The sort function (max1) was fastest for up to 100 elements; it was
about 160% faster for 10 elements vs foreach (max2), and about 50%
faster for 100 elements.  The map function (max3) was slowest, which
is not surprising because it has to construct a brand new array which
is then wastefully discarded.

For 1000 or more elements, the foreach function (max2) was fastest; it
was 10% faster than sort for 1000 elements and more than 100% faster
for 10k elements.  The sort method placed second for 1000 elements,
but was slowest for 10k elements, even slower than the prodigal map
function; O(n ln n) eventually dominates over O(n).

I'm a litttle puzzled as to why max2 (foreach with if modifier) is
consistently about 25% faster than max4 (foreach with ternary operator).
My guess is that the difference is due to how often the assignment is
done.  With the if modifier, the assignment is done only when necessary;
with the ternary operator, the assignment is done for every element of
the array (most of the time uselessly assigning $max = $max).

Some of the functions above could be modified to take an array
reference, rather than copying every element of the array into @_.
This would cut down the subroutine call overhead and speed up
execution, especially for larger arrays.  One could also just avoid
the subroutine call overhead completely, say by inlining:
my $maximum = (sort {$a <=> $b} @array)[-1];

It's also worth noting that if you want both the max and the min, or
the top N values, or something similar, then the sort becomes even
more efficient since it only needs to be done once:
my ($min, $max) = (sort {$a <=> $b} @array)[0, -1];
my ($first, $second, $third) = (sort {$a <=> $b} @array)[-1, -2, -3];
This single sort is still O(n ln n), but this is likely faster than
repeating a O(n) foreach multiple times.  (You could modify the foreach
to return multiple values upon iterating the list once, but that would
sacrifice significant clarity.)

+ Richard J. Barbalace

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




Re: Perl code - Coverage

2002-01-17 Thread Richard J. Barbalace

Rajanikanth Dandamudi <[EMAIL PROTECTED]> writes:
>  Can someone help me in getting the coverage of a perl
>  program. I had used the Coverage  module  of the perl
>  distribution by issuing a command:
>  perl -d:Coverage script_name [ args ]

There's very little documentation in Devel::Coverage's perldoc,
but some more is in its README file:
http://theoryx5.uwinnipeg.ca/CPAN/data/Devel-Coverage/README.html

This package looks like a good idea, but sounds like it is still too
early to work with usefully.  The package does not seem to have been
updated in the past year, so you might ask the author if he has a
newer version, or is working on one.

+ Richard J. Barbalace
  Cambridge, MA

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




Re: Resume after die?

2002-01-04 Thread Richard J. Barbalace

Jenda writes:
> Well ... what about just ... making the eval{} block smaller?
> 
> eval {
># Code where an error may occur
>exception_causing_method();
> };
> if ($@) { ... }
> # Code where I want to resume after handling the exception
> print "Continuing\n";

Let's assume I'm trying to write a generalized resumptive error
handler.  I don't have control over what the eval block (or
equivalent) will be, nor do I know how to modify its contents.

> Another thing ... what EXACTLY do you mean by "resume with 
> next statement". Say your eval{} block called function Foo(), which 
> called Bar(). And somewhere in the middle of Bar() occured an 
> exception.Do you want to continue with Bar(). Go back into Foo() 
> just below he call to Bar()? Go to the line of the eval{} block below 
> the call to Foo() ?
> I guess the last one, but ...

The first:  continue with the next line after where the exception was
triggered, such that all state in any current functions is the same.

> Anyway to tell the truth you could do this :
> 
>   eval {
>   print "Ahoj\n";
>   $y = 0;
>   $x = 1/$y;
>   LEJBL: print "Cau\n";
>   };
>   if ($@) {
>   print "ERROR: $@\n";
>   goto LEJBL;
>   }

That's closer, but is it possible without inserting a label or using
a goto?  Assume the code that might trigger the error (the eval block
or equivalent) is given to me.

> P.S.: You come from VB? "On Error Resume Next", "On Error 
> Goto errHandler" and "Resume Next" ... I've never got used to that 
> crazy way of doing things.

No, I've never used VB.  I'm just looking into doing resumptions in
Perl

+ Richard

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




Re: Resume after die?

2002-01-04 Thread Richard J. Barbalace

I wrote:
> I'm looking into ways to do resumptive exception handling in Perl.  For
> example, I have something equivalent to:
>eval {
>   # Code where an error may occur
>   die "Here's an exception";
>   # Code where I want to resume after handling the exception
>   print "Continuing\n";
>};
>if ($@) {
>   # Handle the exception
>   # Resume at the line following the exception
>}
> 
> Is there a way of resuming after the die statement?  If not, is there
> a standard way of resuming after exception handling in Perl?  I have
> code that allows redoing the entire eval block or simply continuing
> after the eval block, but I have not found any way to resume inside
> the eval block.

Maybe I wasn't clear so people took the "die" command too literally.
There might not be a "die" command in the code at all.  It might be
a subroutine that calls "die", or some statement that causes a runtime
exception, or any other means of raising a normally-fatal exception:
 eval {
# Code where an error may occur
exception_causing_method();
# Code where I want to resume after handling the exception
print "Continuing\n";
 };

I want to handle the exception and then resume execution at the following
line, regardless of how the exception is caused.  Can anyone recommend a
technique to do this type of resumptive exception handling in perl?  I
suspect it involves something more complicated than an eval {BLOCK} form.

Thanks.
+ Richard J. Barbalace
  Cambridge, MA

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




Resume after die?

2002-01-03 Thread Richard J. Barbalace

I'm looking into ways to do resumptive exception handling in Perl.  For
example, I have something equivalent to:
 eval {
# Code where an error may occur
die "Here's an exception";
# Code where I want to resume after handling the exception
print "Continuing\n";
 };
 if ($@) {
# Handle the exception
# Resume at the line following the exception
 }

Is there a way of resuming after the die statement?  If not, is there
a standard way of resuming after exception handling in Perl?  I have
code that allows redoing the entire eval block or simply continuing
after the eval block, but I have not found any way to resume inside
the eval block.

+ Richard J. Barbalace
  Cambridge, MA

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




Re: Login methods / passing values

2001-11-16 Thread Richard J. Barbalace

Etienne Marcotte <[EMAIL PROTECTED]> writes:
> I have a webpage where a user logs in to get administrative options.
> The main admin page directs to different sections (perl scripts) for
> different table manipulations of the database [...]
> 
> What are your comments regarding those methods / do you suggest
> something else $ which one would you use / speed?

This depends on how much security you require and what threats and
risks you are trying to minimize.

> - Users logs in, when choosing an option, values for username, pass,
> userID, etc are sent to the new script via POST in a form.

This is bad because you are sending the password over the network with
each call.  If you are not encrypting the information, then someone
sniffing your network can get the username/password.  Even if
encrypting the information somehow, repeatedly submitting passwords
over the network is not recommended.

The password, etc. is also viewable in the page source to anyone using
the browser, which includes the legitimate user and anyone who might
pass by their computer while they go off to fetch a cup of coffee.

> - Users logs in, script sets cookie, when choosing an option, values for
> username, pass, userID, etc are read from the cookie by the called
> script (so the link is not a form with hidden fields but only a link to
> the script name)

Reread "This is bad..." paragraph above.  Same thing applies here.

Substitute "cookie file" for "page source" in the "The password.."
paragraph above.  Same thing applies here.

A better approach is to transmit the username/password encrypted just
the first time.  Verify this information the first time and create a
unique non-forgeable identifier (or token or cookie) containing no
information about the username or password; someone should not be able
to obtain the username/password from this identifier or create an
identifier that is valid without logging in.  The identifier might be
stored in a DB along with the user id.  Use this identifier for
confirming user actions during this session; if the identifier is
stolen, than the thief only has access for this one session.

You might also limit access with this identifier from a single IP
address, if users will always have a single IP address in a session;
then a stolen identifier can only be used on the same machine as
the original user, which might make it less useful.

There are various ways to do the above.  Talk to your local security
expert for more ideas.

+ Richard J. Barbalace
  <[EMAIL PROTECTED]>
  Cambridge, Massachusetts, USA

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




Re: Off-Topic (200%) - Where are you from? - Results

2001-11-14 Thread Richard J. Barbalace

Etienne Marcotte <[EMAIL PROTECTED]> writes:
> Ok, after 5 days running,
> 101 different persons replyed within 5 days.
> Pretty good:-)

I think that was interesting, but rather than continue this thread,
I'd like to recommend that people include their location in postings
to this list.  I certainly won't remember where everyone is from
otherwise, and it is useful to note a poster's location and time zone
difference.

+ Richard J. Barbalace
  [EMAIL PROTECTED]
  Cambridge, Massachusetts, USA

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




Re: Problem using IF with AND

2001-10-31 Thread Richard J. Barbalace

Kurt writes:
> if ($client ne $newclient and $method ne $newmethod){
> print "something\n";#I'll actually be
> printing this to my report once I get this worked out
> }
> 
> Problem is that this seems to work for only the first set of variables and
> ignores the ones after the "and".  For instance $method could be either
> CMD.EXE or ROOT.EXE.  Any ideas?  I added a line of code to show what the
> strings $newclient and $newmethod contain at each loop and it is correct, so
> I'm a little confused.

Several people suggested using the && operator instead of the 'and'
operator; I doubt this helped.  The 'and' operator is just like the &&
operator, but at a lower precedence so you need not add extra
parentheses.  The code you have is correct, but it might not be doing
what you want to be doing.

Your boolean condition will be true if $client is not equal to
$newclient and also $method is not equal to $newmethod.  A simpler way
of saying that is:  your boolean condition will be false unless $client
equals $newclient or $method equals $newmethod.  The following short
script shows this to be the case:

#!/usr/bin/perl

use strict;
use warnings;

my $client = "client";
my $newclient = "client";
my $method = "method";
my $newmethod = "method";

if ($client ne $newclient and $method ne $newmethod) {
print "1 should NOT be printed - $client and $newclient are the same\n";
}

$newclient = "something else";
if ($client ne $newclient and $method ne $newmethod) {
print "2 should NOT be printed - $method and $newmethod are the same\n";
}

$newmethod = "something else";
if ($client ne $newclient and $method ne $newmethod) {
print "3 should be printed\n";
}

unless ($client eq $newclient or $method eq $newmethod) {
print "4 should be printed - this is identical to 3\n";
}

exit;

This correctly prints:
3 should be printed
4 should be printed - this is identical to 3

My guess is that you might want to be using the 'or' operator instead
of the 'and' operator:
if ($client ne $newclient or $method ne $newmethod) {

In this case, if either $client differs from $newclient or $method
differs from $newmethod, your condition will be true and the print
statement will run.  Again, a simpler way of writing that is:
unless ($client eq $newclient and $method eq $newmethod) {

Another thing to notice is that perl only evaluates the minimum
necessary to reach a conclusion on the state of the boolean.  For
'and' and &&, if the first part ($client ne $newclient) is false, the
whole condition must be false, so the second part ($method ne
$newmethod) is not evaluated.  Similarly for 'or' and ||, if the first
part is true, the whole condition must be true, so the second part is
not evaluated.

+ Richard J. Barbalace
  (a little behind on the list digests)

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




Re: Array of Hashes?

2001-09-24 Thread Richard J. Barbalace

Jonathan Batchelor writes:

> I have a data structure similar to the following:
> 
> @hosts = ( list of hashes like below ... );
> %hosts = ( name => "hostname",
>ipaddr => "www.xxx.yyy.zzz",
>location => "location"
>  );
> 
> How can produce a sorted list of the hashes based on the hostname and then
> access each hash to print the details.
> 
> Or is there a better way of organising my data?

There might be better way.  It's not clear to me that you need the
array of hashes at all.  If you don't, try the following.

Create a hash of hashes:
   %hosts = ( hostname1 => {ipaddr => "www.xxx.yyy.zzz",
location => "location"},
  hostname2 => {ipaddr => "www.xxx.yyy.zzz",
location => "location"},
  .
);

To get a sorted list of hostnames, do:
   @hostnames = sort keys %hosts;

Now you can either use the alphabetically sorted hostnames array, or
quickly look up a particular hostname with the hosts hash.  If you do
the latter often, the hash will be more efficient than looking through
the array.  For example, if you want to allow a user to enter a
hostname and look up its address, using the hash will probably be
faster and easier.  If you only ever want to access the data sorted by
hostname, however, there's no reason not to use an array of hashes.

To print out the data you can do something like:
foreach my $hostname (@hostnames) {
print "Hostname: $hostname\n";
    print "Address:  ".$hosts{$hostname}->{ipaddr}."\n";
print "Location: ".$hosts{$hostname}->{location}."\n";
}

+ Richard J. Barbalace

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




Re: Math::BigInt

2001-09-14 Thread Richard J. Barbalace

Gibbs Tanton writes:
>  You might want to try Math::BigFloat instead.

I originally wrote:
> I'm trying to perform the following calculation:
> $value = ($float + $integer) * 10;
> $string = "$value:test";

I now have code like the following:
use Math::BigFloat;

# Initial values
my $float   = 1000123123.12345;
my $integer = 123456789;
my $factor  = 100;
my $string  = ":test";
my $value;

$value = Math::BigFloat->new($float);
print "Value 1: $value.\n";
$value = Math::BigFloat->new($value->fadd($integer));
print "Value 2: $value.\n";
$value = Math::BigFloat->new($value->fmul($factor));
print "Value 3: $value.\n";
$value =~ s/.$//;  # Remove decimal point
print "Value 4: $value.\n";
$value .= $string; # Append string
print "Value 5: $value.\n";

This outputs:
Value 1: 1000123123.12345.
Value 2: 1123579912.12345.
Value 3: 1123579912123450..
Value 4: 1123579912123450.
Value 5: 1123579912123450:test.

It seems awful to call Math::BigFloat->new() three times to do the
calculation part.  Is there a simpler way of doing this?

+ Richard J. Barbalace
  <[EMAIL PROTECTED]>

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




Math::BigInt

2001-09-13 Thread Richard J. Barbalace

Hi.

I'm trying to perform the following calculation:
$value = ($float + $integer) * 10;
$string = "$value:test";

Here, I know $float has a resolution of millionths.  That is, $float
multiplied by 1,000,000 should be an integer.  However, $float is very
large, and multiplying by 1,000,000 causes it to exceed perl's integer
range.  Thus I would like to use Math::BigInt, but I am having trouble
getting it to work with the floating point value.

For example, if $value is 1234567890123456.123456, and $integer is
1, then I want the final resulting string $string to be
"1234567890123457123456:test".

When I tried using BigInt with floating point numbers like $float, I
end up with NaN and then get errors like:
Can't locate object method "badd" via package "NaN"...

Any ideas on how to do this conversion simply?  Thanks.

+ Richard J. Barbalace
  <[EMAIL PROTECTED]>



-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




Re: beginners Digest 9 Aug 2001 12:42:51 -0000 Issue 305

2001-08-09 Thread Richard J. Barbalace

"Kevin Hundley" <[EMAIL PROTECTED]> writes:
> The code does exactly what I want.  However, I get the following message
> (when the perl -w option is enabled):
> Use of uninitialized value at (eval 11) line 17.
> 
> Is this message something I should just live with (or turn off the -w
> option)?  Or is this a minor bug in the CGI module?  Or, being a newbie to
> Perl, am I doing something else wrong?

Older versions of CGI.pm had a minor bug where included scripts
triggered this warning.  It's been fixed in the newer versions,
so try upgrading your copy of CGI.pm to the most recent version.
I suspect the problem will then just disappear.

+ Richard

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




Re: beginners Digest 8 Aug 2001 19:36:47 -0000 Issue 302

2001-08-08 Thread Richard J. Barbalace

> From: "Scott" <[EMAIL PROTECTED]>
> To: "Joe Bellifont" <[EMAIL PROTECTED]>,
>   <[EMAIL PROTECTED]>
> Subject: RE: modules
> Date: Wed, 8 Aug 2001 10:29:05 -0700
> 
> Here is some code that will list all installed modules
> 
> #!/usr/bin/perl -w
> use ExtUtils::Installed;
> my $instmod = ExtUtils::Installed->new();
> foreach my $module ($instmod->modules()) {
> my $version = $instmod->version($module) || "???";
>print "$module -- $version\n";
> }

Hm, I had also wondered if there was a simple way of doing this.
I just tried this code and found that it fails.  I get the output:
Can't stat /usr/local/lib/perl/5.6.0: No such file or directory
Perl -- 5.6.0

Nothing more, and I have many modules installed.  The directory
mentioned is in my @INC (by default) but does not exist.  Is it a bug
that ExtUtils::Installed->new() fails on non-existent directories?
perl itself certainly tolerates the non-existent directories it puts
in @INC.

+ Richard

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




Re: Inheritance of package global variables

2001-06-28 Thread Richard J. Barbalace

Michael Fowler <[EMAIL PROTECTED]> replies:
> Exporting is usually a bad idea when dealing with classes, it breaks
> encapsulation.  You should probably setup a class method for this.
> 
> That being said, you can export variables just like you export any other
> data type, with Exporter; perldoc Exporter or
> http://www.perldoc.com/perl5.6/lib/Exporter.html.

I don't really want to export the variables; I'm not modifying them in
the parent package, just copying and expanding them in the inheriting
package.

Here's what I'm really trying to do.  I have a set of packages that
closely inherit from a base class.  The base class and all subclasses
have some common attributes; the subclasses may add more attributes to
this set.  Some attributes may be modified in certain ways and some
may not be modified.  As such, I'm using separate accessor methods
get() and set() for setting the attributes, as in:
$attribute_value = $object->get('attribute_name');
$object->set('attribute_name', $attribute_value);

The 'set' method needs to know what are legal attributes and what are
legal values for a given attribute.  I'm using a hash of attribute
names and regexes to define what are legal values for the allowed
attributes:
# Object attributes are changeable only if their values match the regexes
%Attributes = (
   # Immutable attributes have regexp undefined
   'id' => undef,
   'creator'=> undef,
   'creation_time'  => undef,
   # Mutable attributes have regexp specified
   'name'  => '^.{1,30}$',
   'description'   => '^.{0,255}$',
   .
   );

The 'set' method then uses this hash to verify the names and values of
attributes are acceptable before setting them.  The simplified code
looks something like:
sub set {
# $self->set($name, $value);

# Get parameters and initialize variables
my ($self, $name, $value) = @_;

# Check attribute
die "Invalid attribute $name provided"
unless exists $Attributes{$name};
die "Cannot change attribute $name"
unless defined $Attributes{$name};
die "The provided value for attribute $name is not acceptable"
unless ($value =~ /$Attributes{$name}/);
.
# Set attribute
$self->{$name} = $value;
}

(The real code is more complicated since it allows setting multiple
attributes at once.)

The package inheriting from this parent class might add more attributes:
# La/De/Da/MyPackage.pm
package La::De::Da::MyPackage
.
use base qw( La::De::Da::MyBase ); # Takes care of @ISA and %FIELDS.
use vars qw( %Attributes );# But also need to extend %Attributes.
%Attributes = (
   # MyPackage inherits attributes from MyBase
   %La::De::Da::MyBase::Attributes,
   # Mutable attributes have regexp specified
   'color' => '^(red|green|blue)$',
   'size   => '^(small|medium|large)$',
   'price' => '^\$\d+\.\d\d$',
   );

Another package might define different additional attributes.  For a
'MyPackage' object:
my $object = La::De::Da::MyPackage->new();
$object->set('name', 'Pickle');   # OK
$object->set('description', 'dill');  # OK
$object->set('color', 'green');   # OK
$object->set('size', 'giant');# dies, since not an acceptable value
$object->set('weight', 'heavy');  # dies, since not an acceptable name
$object->set('id', 50);   # dies, since id is unchangeable

This has the advantage of having a single 'set' method in the parent
package that is smart enough to do the necessary error validation for
all inheriting packages, instead of having a separate specialized
'set' method for each package.  This is a real savings since I have a
large number of inheriting packages.

I have not been able to find a perl module that would allow this sort
of inheritance and data validation; does anyone know of one that does
this?  Or can anyone suggest a better way of doing what I want?

+ Richard J. Barbalace



Inheritance of package global variables

2001-06-28 Thread Richard J. Barbalace

Hi.

I feel like I'm asking a lot of questions lately, but this list has
been extremely helpful. :)

I'm writing some packages that inherit from a base class, which has
some fields and some global variables that I want inherited.  I have
code like:
 # La/De/Da/MyBase.pm
 package La::De::Da::MyBase;
 .
 use fields qw( MyField );
 use vars qw( %Attributes );
 %Attributes = ( 'a' => 1, 'b' => 2);

 # La/De/Da/MyPackage.pm
 package La::De::Da::MyPackage
 .
 use base qw( La::De::Da::MyBase ); # Takes care of @ISA and %FIELDS.
 use vars qw( %Attributes );# But also need vars.
 %Attributes = %La::De::Da::MyBase::Attributes;
 $Attributes{'c'} = 3;  # Extend the attributes hash

The 'use base' pragma nicely takes care of the @ISA and %FIELDS
variables for me, but I also need to have the package global variable
%Attributes inherited.  The 'use vars' and assignment in MyPackage is
rather verbose, and I'm wondering if there is a better or terser way
of doing that.  What's the recommended way of inheriting package
global variables?

+ Richard J. Barbalace



Re: package verification

2001-06-26 Thread Richard J. Barbalace


> On Mon, Jun 25, 2001 at 06:13:18PM -0400, Richard J. Barbalace wrote:
> 
> > I'm writing a package that uses another module. This latter module may
> > change somewhat erratically and unreliably, outside of my control.  As
> > a result, I want to have the package test itself and die if it notices
> > that the other module has changed in an incompatible way.  What's a
> > good way of doing this?

Paul Johnson writes:
> What's wrong with just sticking your test at the end of the module?  Any
> code found "lying around" in the module will be run as soon as the
> module is compiled.  This is useful for initialising the module, or
> possibly testing it 

That works if you return to the same package.  For example, if I had a
main package and several sub-packages that inherited from it, the
following works without giving any warning:
 package MyPackage;
 use Flakey;
 .
 package MyPackage::A;
 use vars qw( @ISA );
 @ISA = qw(MyPackage);
 .
 package MyPackage::B;
 use vars qw( @ISA );
 @ISA = qw(MyPackage);
 .
 package MyPackage::C;
 use vars qw( @ISA );
 @ISA = qw(MyPackage);
 .
 package MyPackage;
 # Test if Flakey is compatible with MyPackage

This works fine if you only need to verify the main package.  (And
actually, in my current case I think I can get away with that.)  But
I'm also interested in the more general case of testing the
sub-packages as well.

Trying to do this gives a warning.  For example:
 package MyPackage;
 use Flakey;
 .
 package MyPackage::A;
 .
 package MyPackage::C;
 # Test if Flakey is compatible with MyPackage::C
 use MyPackage;  # Required since we're not in MyPackage

If I want to test each of the sub-packages, I have to "use MyPackage"
(or something equivalent).  Initially I thought the warnings might
result because "use" is really a BEGIN block, but replacing it with
"require" and "import" statements cause other problems.

+ Richard



package verification

2001-06-26 Thread Richard J. Barbalace

Hi.

I'm writing a package that uses another module. This latter module may
change somewhat erratically and unreliably, outside of my control.  As
a result, I want to have the package test itself and die if it notices
that the other module has changed in an incompatible way.  What's a
good way of doing this?

I'm currently doing this by wrapping the entire package in a BEGIN
block, and then adding on some tests in a CHECK block.  My current
package looks like:
#!/usr/bin/perl

BEGIN { # Compilation of packages before testing

package MyPackage;

use strict;
use warnings;
use Flakey;
.
} # End of compilation of packages before testing

CHECK { ## Testing of packages

package MyPackage::Test;
use MyPackage;

# Various tests to ensure compatibility
die "Flakey is not compatible" if ...
.
} # End of testing of packages

1;
__END__

This works well in that any code using MyPackage will properly load
the package if Flakey is compatible and will die if Flakey is or
becomes not compatible.

However, some warnings are issued ("Subroutine foo redefined...")
because I "use MyPackage" in MyPackage::Test.  Is there a way to avoid
these warnings?  Or is there a way to suppress them?

Is there a better way to do this sort of thing?  Long term, I plan to
find a better module than Flakey or incorporate its compatible parts
into MyPackage to manage this problem, but I'm looking for a
short-term fix for now.

+ Richard J. Barbalace



Re: DBI Module

2001-06-22 Thread Richard J. Barbalace

Diego Riano writes:
> I am trying to use de perl DBI module to use a MySQL database.  I want to kno
> where can I find a tutotial or maybe a HowTo (I do not know?) about perl DBI
> module?

In addition to the links already suggested, I recommend getting the
O'Reilly book "Programming the Perl DBI" by Descartes & Bunce.  If
you're going to be doing any substantial development with DBI, this
complete guide to DBI will help you understand DBI, how to work with
different types of databases, and give you a good overview of issues
involved with using databases in general.

If you're new to MySQL too, then I'll also recommend getting the New
Riders book "MySQL" by Paul DuBois.  I have used both books
substantially and found them essential for large projects using Perl
and MySQL.

+ Richard J. Barbalace
  [EMAIL PROTECTED]



caller function

2001-06-20 Thread Richard J. Barbalace

Hi.

I've programmed in Perl for several years, but this feels like a
beginner question.  I'm trying to understand how the built-in function
"caller" works.  The documentation leads me to expect "caller" to do
something other than what it actually does.  I'd like to figure out if
I'm simply misunderstanding what it does or if I'm using it in a way
it wasn't intended to be used.

>From the documentation, I expect the following code to return the
package name, filename, line number, and subroutine name that the
currently executing subroutine was called from:
($package, $filename, $line, $subroutine) = caller();

This does return the package name, filename, and line number as I
expect.  However, it does not return the subroutine name where the
current subroutine was called, but instead the name of the current
subroutine.

Below is some simple code to illustrate this:
1:  #!/usr/bin/perl
2:  
3:  use strict;
4:  use warnings;
5:  
6:  sub c1 {
7:  c2();
8:  }
9:  sub c2 {
10: c3();
11: }
12: sub c3 {
13: my $i = 0;
14: while (my ($package, $filename, $line, $subroutine) = caller ($i)) {
15: print "CALLER $i\n";
16: print "Package: $package.\n";
17: print "Filename:$filename.\n";
18: print "Line:$line.\n";
19: print "Subroutine:  $subroutine.\n";
20: $i++;
21: }
22: }
23: 
24: c1();
25: exit;

Part of the output looks like:
CALLER 0
Package: main.
Filename:caller.pl.
Line:10.
Subroutine:  main::c3.
.

If my understanding of the documentation is correct, the subroutine
name should be main::c2 (which called c3 at line 10), not main::c3
(the name of the current subroutine).  I'm having trouble
understanding why "caller" would be designed to return the name of the
current subroutine instead of the caller subroutine.

I'm interested in getting the name of the calling subroutine for error
handling reasons.  Specifically, I'm trying to extend the Error perl
module to report more data about errors (such as the time an error
occurred and of course the subroutine in which the error occurred);
this information would be logged to a file.  I currently am using code
similar to the following to extract the data I need:
report_error {
local $Error::Depth = $Error::Depth + 1;
.
my ($package, $filename, $line) = caller($Error::Depth - 1);
my ($subroutine) = (caller($Error::Depth))[3];
.
}

As you can see, I have to use two separate "caller" lines to get the
line number of the error and the subroutine name in which the error
occurred.  This is a bit of an ugly nuisance, which makes me think I'm
doing something wrong.

So, I guess my questions are:
1) Does anyone else feel misled by the documentation on "caller"?
2) Does anyone else find the subroutine result of "caller" confusing?
3) Why does "caller" return the "wrong" subroutine name?  Or perhaps,
   why is the subroutine name returned by "caller" the right one to
   return?
4) How is "caller" usually used by perl experts?
5) Is there something wrong with my use of "caller" to find the error
   data I want?
6) Is there a better way of getting this data?

Any enlightenment you can provide would be appreciated.

+ Richard J. Barbalace
  <[EMAIL PROTECTED]>