sifukurt has asked for the wisdom of the Perl Monks concerning the following question:
I've got a module that I'm working on where I am pre-caching a number of very large constants, created with Math::BigFloat. My problem is this: I've got 10 or 12 of these very large constants, but for the most part, only one or two of them are going to used at any given time. That being the case, I don't want to automatically dump all of them into memory, only the ones that a user asks for. For example, I've got the square root of 2 and the square root of 5 ($_sqrt2_ and $_sqrt5_, respectively) as two of these constants. Let's say I only need $_sqrt2_. What would be the best method for creating these via Math::BigFloat "on demand?" My first thought was to make a CONSTANT() routine where the user would pass the name of the constant they want and have it created at that time. It seems to me, though, that there should be a better way. I did some digging through the search here, but didn't find anything (perhaps I was searching for the wrong thing?). Any suggestions?
Many thanks.
___________________
Kurt
UPDATE (11-Feb-2002 10:21:38 AM): By way of further clarification, the problem isn't that I'm concerned about the calculation time of these constants. I'm pre-calculating them and I'm subsequently hard-coding them as Math::BigFloat objects. My concern is a memory issue since some of these constants are very, very large. I suppose a few extra kb of memory probably isn't going to make much of a difference, but it is The Principle of The Thing. My original plan was to use an accessor method similar to that described by hossman to avoid dumping all of these constants into memory if only one or two (or possibly even none) are going to be used in a given script. Forgive me for showing my ignorance here, but does the Tie::Scalar method that japhy used accomplish this? I've never used Tie::Scalar before, so I'm a little in the dark, even after reading the docs.
Re: Pre-caching large constants
by japhy (Canon) on Feb 08, 2002 at 22:12 UTC
|
Here's Tie::Scalar::Once. It's not very complex.
# delays determination of a scalar's value until needed
package Tie::Scalar::Once;
require Exporter;
@ISA = qw( Exporter );
@EXPORT = qw( delay );
use strict;
sub delay {
tie $_[0], __PACKAGE__, \$_[0], $_[1];
}
sub TIESCALAR {
my ($class, $var, $code) = @_;
bless [ $var, $code ], $class;
}
sub FETCH {
my ($self) = @_;
my $val = $self->[1]->();
untie ${ $self->[0] };
${ $self->[0] } = $val;
}
sub STORE {
require Carp;
Carp::croak("Can't store $_[1] to a constant");
}
1;
Use it like so:
use Tie::Scalar::Once;
delay $x => sub { sqrt 2 };
# ...
if ($you_need_to) { print $x }
_____________________________________________________
Jeff[japhy]Pinyan:
Perl,
regex,
and perl
hacker.
s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??; | [reply] [d/l] [select] |
|
Acctually, it looks like a more elaborate version of this allready exists as Data::Lazy.
| [reply] |
Re: Pre-caching large constants
by chromatic (Archbishop) on Feb 08, 2002 at 21:26 UTC
|
Write a new class derived from Tie::Scalar. In its FETCH() method, create the constant with Math::BigFloat, then replace the tied scalar with the constant. The float will only be created on the first access.
Disclaimer: I have not (yet) tried this, but I'm pretty confident.
Update: I have tried this, and I'm reinventing Oroborous. It's not as easy as it first sounded. | [reply] |
(bbfu) (Memoize) Re: Pre-caching large constants
by bbfu (Curate) on Feb 09, 2002 at 02:02 UTC
|
Or, you could go with a pre-built solution, a la Memoize.
bbfu
Seasons don't fear The Reaper.
Nor do the wind, the sun, and the rain.
We can be like they are.
| [reply] |
Re: Pre-caching large constants
by runrig (Abbot) on Feb 08, 2002 at 22:53 UTC
|
Just a not too well thought out idea, but you could put
the values after a _DATA_ tag so that they're there to read
in the first time, e.g: __DATA__
SQRT5|2.blahblahblah
SQRT2|1.blahblahblah
E|2.more blahblah
The logic to control the reading in is left up to you,
anyway, others seem to have a handle on part of that,
while I don't have the time at the moment. I don't
really like the AutoLoader solution, it seems nifty, but
then you get too many reports from people who install
the module incorrectly (just copying the pm file to a
directory in @INC, or using 'use lib',
when you really need to do the 'perl Makefile.PL, make...etc.),
and then ask "Why doesn't this work?".
And then again, a few extra 500 byte strings really shouldn't
make all that big of a difference...
| [reply] [d/l] |
Re: Pre-caching large constants
by lestrrat (Deacon) on Feb 08, 2002 at 21:22 UTC
|
Check out AutoLoader or SelfLoader.
They are nifty!
apparently some people are not satisfied by the admission of mistake in a follow up post in the thread...
| [reply] |
|
I don't think SelfLoader or AutoLoader are really what he
wants here. They are designed for situations in which
the compilation of code is very expensive, and you don't
want to bother unless the code is needed.
In this case, it sounds like the code to populate the
constants is relatively simple, and won't take long to
compile, it just takes a while to run.
This screams accessor to me.
Instead of making these constants part of your 'public'
API, make them internal, and write an accessor for them
that initializes them the first time it calls, and
returns them everytime after that:
package mypackage;
my $sqrt_2 = undef; # not visible outside of mypackage
sub get_sqrt_2 {
unless (defined $sqrt_2) {
# do a bunch of work to set $sqrt_2
}
return $sprt_2;
}
| [reply] [d/l] |
|
| [reply] |
|
|