# Version 0.05 alpha $Revision: 1.3 $ $Date: 1998/09/05 03:44:04 $

=head1 TO DO

=over 4

=item *

We should extend the benchmarking module to allow

	timethis(main, { MEMOIZED => [ suba, subb ] })

What would this do?  It would time C<main> three times, once with
C<suba> and C<subb> unmemoized, twice with them memoized.

Why would you want to do this?  By the third set of runs, the memo
tables would be fully populated, so all calls by C<main> to C<suba>
and C<subb> would return immediately.  You would be able to see how
much of C<main>'s running time was due to time spent computing in
C<suba> and C<subb>.  If that was just a little time, you would know
that optimizing or improving C<suba> and C<subb> would not have a
large effect on the performance of C<main>.  But if there was a big
difference, you would know that C<suba> or C<subb> was a good
candidate for optimization if you needed to make C<main> go faster.

=item * 

Maybe a tied-hash interface to the memo-table, which a hook to
      automatically populate an entry if no value is there yet?

=item * 

Perhaps C<memoize> should return a reference to the original function
as well as one to the memoized version?  But the programmer could
always construct such a reference themselves, so perhaps it's not
necessary.  We save such a reference anyway, so a new package method
could return it on demand even if it wasn't provided by C<memoize>.
We could even bless the new function reference so that it could have
accessor methods for getting to the original function, the options,
the memo table, etc.

=item *

The TODISK feature is not ready yet.  It will have to be rather
complicated, providing options for which disk method to use (GDBM?
DB_File?  Flat file?  Storable?  User-supplied?) and which stringizing
method to use (FreezeThaw?  Marshal?  User-supplied?)

=item *

Maybe an option for automatic expiration of cache values?  (`After one
day,' `After five uses,' etc.)  

=item *

Put in a better example than C<fibo>.  Show an example of a
nonrecursive function that simply takes a long time to run.
C<getpwuid> for example?  But this exposes the bug that you can't say
C<memoize('getpwuid')>, so perhaps it's not a very good example.

Well, I did add the ColorToRGB example, but it's still not so good.
These examples need a lot of work.  C<factorial> might be a better
example than C<fibo>.  

=item *

Add more regression tests for normalizers.

=item *

Maybe resolve normalizer function to code-ref at memoize time instead
of at function call time for efficiency?  I think there was some
reason not to do this, but I can't remember what it was.

=item *

Add more array value tests to the test suite.

=item *

Fix that `Subroutine u rededined ... line 484' message.

=item *

Get rid of any remaining *{$ref}{CODE} or similar magic hashes. 

=item *

There should be an option to dump out the memoized values or to
otherwise traverse them.

=item *

There was probably some other stuff that I forgot.


=item * 

Here's the preliminary interface spec for the C<TODISK> option:
`memoize' takes options named C<SCALAR_CONTEXT> and C<LIST_CONTEXT>.
Legal values are

	MEMORY
	TIE
	FAULT
	MERGE

or a reference to a list whose first element is one of these.  The
default for both is MEMORY, which means that Perl's builtin hashes are
used, the way they are now.  FAULT means that the function should
never be called in scalar/list context, and that Memoize should croak
if it is.  TIE means that the hash will be tied; it's usaully written
as

	[TIE, packagename, argument-list]

which specifies the package name and arguments for the tie.  Memoize
will load the package if appropriate.  Thus

	[TIE, Storable, filename, ...]
	[TIE, DB_File, filename, flags, mode, ...]
	[TIE, MLDBM, DB_File, ... ]

MERGE means that return values in the specified context will be stored
in the same structure that is used for the other context.  For
example, suppose you have a function which always returns a scalar,
and doesn't care whether it was called in scalar or list context.  You
don't want to store its list-context reutrn separately from its
scalar-context return, because they're going to be the same anyway,
and if you stored them separately, you'd waste a call and a cache
slot.  So you say LIST_CONTEXT => MERGE, and then list context is
considered the same as scalar context.

You can also use MERGE with a normalizer to get the list-context and
scalar-context returns stored in the same database without conflicting
with each other.

If you specify MERGE for both, it's either an error or else you get
them stored in one in-memory hash, or something.

=item *

Include an example that caches DNS lookups.

=item *

Make tie for Storable (Memoize::Storable)

=item*

Make tie for DBI  (Memoize::DBI)

=item *

Tie for SDBM doesn't work.  Can't subclass SDBM?  Why not?

=item *

I think there's a bug.  See `###BUG'.

=item *

Docs / code inconsistent about SCALAR_CONTEXT vs SCALAR_CACHE.
Make up your mind.

Decision:  SCALAR_CACHE.

=item * 

Storable probably can't be done, because it doesn't allow updating.
Maybe a different interface that supports readonly caches fronted by a
writable in-memory cache?  A generic tied hash maybe?

	FETCH {
	  if (it's in the memory hash) {
	    return it
	  } elsif (it's in the readonly disk hash) {
	    return it
	  } else { 
	    not-there
	  }
	}

	STORE {
	  put it into the in-memory hash
	}

Maybe `save' and `restore' methods?

=item *

Maybe add in TODISK after all, with TODISK => 'filename' equivalent to

	SCALAR_CACHE => [TIE, Memoize::SDBM_File, $filename, O_RDWR|O_CREAT, 0666],
	LIST_CACHE => MERGE

=back