|We don't bite newbies here... much|
Breaking Tie::Hash into three modulesby afoken (Canon)
|on Sep 08, 2018 at 18:26 UTC||Need Help??|
This meditation was triggered by Re^3: How to tie a hash to a class.
Why can we do this ...
... but not this?
Why do we have to write this instead?
Or, even worse, this, following the documentation found in Tie::Hash?
A little bit of history
Well, at some point in time, someone must have thought it was clever to put all three classes Tie::Hash, Tie::StdHash, and Tie::ExtraHash into the same file, Tie/Hash.pm. Looking at https://perl5.git.perl.org/perl.git/history/HEAD:/lib/Tie/Hash.pm, that must have happened before 1996-02-03. So this oddity is embedded deep in Perl's history.
At that time, Tie::Hash was still named TieHash, and Tie::StdHash was still named TieHash::Std. Tie::ExtraHash did not exist. And for reasons that are not clear to me, TieHash::Std inherited from TieHash. TieHash::Std reimplemented each and every method, and so only new() was really inherited from TieHash. That is the most useless method in the entire file, because tie never calls it. The TieHash::TIEHASH() constructor adds some extra work just to check for a new() implementation, and that's still there.
Three days after the first version, the classes were renamed to their current names.
Six years later, Tie::ExtraHash appeared in the same file, and it did NOT inherit from Tie::Hash. At the same time, Tie::StdHash stopped inheriting the nonsense new() constructor from Tie::Hash:
In all of the following versions up to the latest from 2013, Tie::ExtraHash never started inherited from Tie::Hash, and the @ISA line in Tie::StdHash was never commented back in.
Cleaning up the mess
As shown, Tie::ExtraHash never inherited from Tie::Hash, so it is completely safe to move it into a separate file. Just cut the last 13 lines from Tie/Hash.pm and paste them into a new file Tie/ExtraHash.pm:
For the last 16 years, it seems that nobody complained about Tie::StdHash no longer inheriting the useless new() from Tie::Hash. So I am very sure that we can also move that class safely out of Tie/Hash.pm. From the edited Tie/Hash.pm, cut the last 17 lines and paste them into a new file Tie/StdHash.pm. Add a trailing 1; and remove the @ISA line completely:
The most obvious problem first: Append a trailing 1; or else loading Tie::Hash will fail.
Now that we have cleaned up everything, legacy knocks at the door, complaining about modules failing to inherit from Tie::StdHash after loading only Tie::Hash. So, we have to load the two modules, just to avoid legacy trouble. Adding two use lines is easy:
A little bit of cleaning up
Both Tie::StdHash and Tie::ExtraHash lack a version number, so add our $VERSION = '1.06' to both files, and bump $VERSION in Tie::Hash to 1.06, too.
All three classes should use strict; use warnings;.
Tie::StdHash and Tie::ExtraHash have no POD at all. We could work around with something like this:
Instead of adding workarounds, we could clean up the POD in Tie::Hash, move the parts documenting Tie::StdHash and Tie::ExtraHash into the respective files, and clean up the examples to 21st century Perl.
Here is a diff, based on the current HEAD:
Should anyone get paranoid about legal stuff: This diff is free software, use it under the same license as Perl (perlartistic).
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)