summaryrefslogtreecommitdiffstats
path: root/upstream/debian-unstable/man1/perltie.1
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:43:11 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:43:11 +0000
commitfc22b3d6507c6745911b9dfcc68f1e665ae13dbc (patch)
treece1e3bce06471410239a6f41282e328770aa404a /upstream/debian-unstable/man1/perltie.1
parentInitial commit. (diff)
downloadmanpages-l10n-fc22b3d6507c6745911b9dfcc68f1e665ae13dbc.tar.xz
manpages-l10n-fc22b3d6507c6745911b9dfcc68f1e665ae13dbc.zip
Adding upstream version 4.22.0.upstream/4.22.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'upstream/debian-unstable/man1/perltie.1')
-rw-r--r--upstream/debian-unstable/man1/perltie.11361
1 files changed, 1361 insertions, 0 deletions
diff --git a/upstream/debian-unstable/man1/perltie.1 b/upstream/debian-unstable/man1/perltie.1
new file mode 100644
index 00000000..b0af3168
--- /dev/null
+++ b/upstream/debian-unstable/man1/perltie.1
@@ -0,0 +1,1361 @@
+.\" -*- mode: troff; coding: utf-8 -*-
+.\" Automatically generated by Pod::Man 5.01 (Pod::Simple 3.43)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>.
+.ie n \{\
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds C`
+. ds C'
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\"
+.\" If the F register is >0, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.\"
+.\" Avoid warning from groff about undefined register 'F'.
+.de IX
+..
+.nr rF 0
+.if \n(.g .if rF .nr rF 1
+.if (\n(rF:(\n(.g==0)) \{\
+. if \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. if !\nF==2 \{\
+. nr % 0
+. nr F 2
+. \}
+. \}
+.\}
+.rr rF
+.\" ========================================================================
+.\"
+.IX Title "PERLTIE 1"
+.TH PERLTIE 1 2024-01-12 "perl v5.38.2" "Perl Programmers Reference Guide"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH NAME
+perltie \- how to hide an object class in a simple variable
+.IX Xref "tie"
+.SH SYNOPSIS
+.IX Header "SYNOPSIS"
+.Vb 1
+\& tie VARIABLE, CLASSNAME, LIST
+\&
+\& $object = tied VARIABLE
+\&
+\& untie VARIABLE
+.Ve
+.SH DESCRIPTION
+.IX Header "DESCRIPTION"
+Prior to release 5.0 of Perl, a programmer could use \fBdbmopen()\fR
+to connect an on-disk database in the standard Unix \fBdbm\fR\|(3x)
+format magically to a \f(CW%HASH\fR in their program. However, their Perl was either
+built with one particular dbm library or another, but not both, and
+you couldn't extend this mechanism to other packages or types of variables.
+.PP
+Now you can.
+.PP
+The \fBtie()\fR function binds a variable to a class (package) that will provide
+the implementation for access methods for that variable. Once this magic
+has been performed, accessing a tied variable automatically triggers
+method calls in the proper class. The complexity of the class is
+hidden behind magic methods calls. The method names are in ALL CAPS,
+which is a convention that Perl uses to indicate that they're called
+implicitly rather than explicitly\-\-just like the \fBBEGIN()\fR and \fBEND()\fR
+functions.
+.PP
+In the \fBtie()\fR call, \f(CW\*(C`VARIABLE\*(C'\fR is the name of the variable to be
+enchanted. \f(CW\*(C`CLASSNAME\*(C'\fR is the name of a class implementing objects of
+the correct type. Any additional arguments in the \f(CW\*(C`LIST\*(C'\fR are passed to
+the appropriate constructor method for that class\-\-meaning \fBTIESCALAR()\fR,
+\&\fBTIEARRAY()\fR, \fBTIEHASH()\fR, or \fBTIEHANDLE()\fR. (Typically these are arguments
+such as might be passed to the \fBdbminit()\fR function of C.) The object
+returned by the "new" method is also returned by the \fBtie()\fR function,
+which would be useful if you wanted to access other methods in
+\&\f(CW\*(C`CLASSNAME\*(C'\fR. (You don't actually have to return a reference to a right
+"type" (e.g., HASH or \f(CW\*(C`CLASSNAME\*(C'\fR) so long as it's a properly blessed
+object.) You can also retrieve a reference to the underlying object
+using the \fBtied()\fR function.
+.PP
+Unlike \fBdbmopen()\fR, the \fBtie()\fR function will not \f(CW\*(C`use\*(C'\fR or \f(CW\*(C`require\*(C'\fR a module
+for you\-\-you need to do that explicitly yourself.
+.SS "Tying Scalars"
+.IX Xref "scalar, tying"
+.IX Subsection "Tying Scalars"
+A class implementing a tied scalar should define the following methods:
+TIESCALAR, FETCH, STORE, and possibly UNTIE and/or DESTROY.
+.PP
+Let's look at each in turn, using as an example a tie class for
+scalars that allows the user to do something like:
+.PP
+.Vb 2
+\& tie $his_speed, \*(AqNice\*(Aq, getppid();
+\& tie $my_speed, \*(AqNice\*(Aq, $$;
+.Ve
+.PP
+And now whenever either of those variables is accessed, its current
+system priority is retrieved and returned. If those variables are set,
+then the process's priority is changed!
+.PP
+We'll use Jarkko Hietaniemi <\fIjhi@iki.fi\fR>'s BSD::Resource class (not
+included) to access the PRIO_PROCESS, PRIO_MIN, and PRIO_MAX constants
+from your system, as well as the \fBgetpriority()\fR and \fBsetpriority()\fR system
+calls. Here's the preamble of the class.
+.PP
+.Vb 5
+\& package Nice;
+\& use Carp;
+\& use BSD::Resource;
+\& use strict;
+\& $Nice::DEBUG = 0 unless defined $Nice::DEBUG;
+.Ve
+.IP "TIESCALAR classname, LIST" 4
+.IX Xref "TIESCALAR"
+.IX Item "TIESCALAR classname, LIST"
+This is the constructor for the class. That means it is
+expected to return a blessed reference to a new scalar
+(probably anonymous) that it's creating. For example:
+.Sp
+.Vb 3
+\& sub TIESCALAR {
+\& my $class = shift;
+\& my $pid = shift || $$; # 0 means me
+\&
+\& if ($pid !~ /^\ed+$/) {
+\& carp "Nice::Tie::Scalar got non\-numeric pid $pid" if $^W;
+\& return undef;
+\& }
+\&
+\& unless (kill 0, $pid) { # EPERM or ERSCH, no doubt
+\& carp "Nice::Tie::Scalar got bad pid $pid: $!" if $^W;
+\& return undef;
+\& }
+\&
+\& return bless \e$pid, $class;
+\& }
+.Ve
+.Sp
+This tie class has chosen to return an error rather than raising an
+exception if its constructor should fail. While this is how \fBdbmopen()\fR works,
+other classes may well not wish to be so forgiving. It checks the global
+variable \f(CW$^W\fR to see whether to emit a bit of noise anyway.
+.IP "FETCH this" 4
+.IX Xref "FETCH"
+.IX Item "FETCH this"
+This method will be triggered every time the tied variable is accessed
+(read). It takes no arguments beyond its self reference, which is the
+object representing the scalar we're dealing with. Because in this case
+we're using just a SCALAR ref for the tied scalar object, a simple $$self
+allows the method to get at the real value stored there. In our example
+below, that real value is the process ID to which we've tied our variable.
+.Sp
+.Vb 10
+\& sub FETCH {
+\& my $self = shift;
+\& confess "wrong type" unless ref $self;
+\& croak "usage error" if @_;
+\& my $nicety;
+\& local($!) = 0;
+\& $nicety = getpriority(PRIO_PROCESS, $$self);
+\& if ($!) { croak "getpriority failed: $!" }
+\& return $nicety;
+\& }
+.Ve
+.Sp
+This time we've decided to blow up (raise an exception) if the renice
+fails\-\-there's no place for us to return an error otherwise, and it's
+probably the right thing to do.
+.IP "STORE this, value" 4
+.IX Xref "STORE"
+.IX Item "STORE this, value"
+This method will be triggered every time the tied variable is set
+(assigned). Beyond its self reference, it also expects one (and only one)
+argument: the new value the user is trying to assign. Don't worry about
+returning a value from STORE; the semantic of assignment returning the
+assigned value is implemented with FETCH.
+.Sp
+.Vb 5
+\& sub STORE {
+\& my $self = shift;
+\& confess "wrong type" unless ref $self;
+\& my $new_nicety = shift;
+\& croak "usage error" if @_;
+\&
+\& if ($new_nicety < PRIO_MIN) {
+\& carp sprintf
+\& "WARNING: priority %d less than minimum system priority %d",
+\& $new_nicety, PRIO_MIN if $^W;
+\& $new_nicety = PRIO_MIN;
+\& }
+\&
+\& if ($new_nicety > PRIO_MAX) {
+\& carp sprintf
+\& "WARNING: priority %d greater than maximum system priority %d",
+\& $new_nicety, PRIO_MAX if $^W;
+\& $new_nicety = PRIO_MAX;
+\& }
+\&
+\& unless (defined setpriority(PRIO_PROCESS,
+\& $$self,
+\& $new_nicety))
+\& {
+\& confess "setpriority failed: $!";
+\& }
+\& }
+.Ve
+.IP "UNTIE this" 4
+.IX Xref "UNTIE"
+.IX Item "UNTIE this"
+This method will be triggered when the \f(CW\*(C`untie\*(C'\fR occurs. This can be useful
+if the class needs to know when no further calls will be made. (Except DESTROY
+of course.) See "The \f(CW\*(C`untie\*(C'\fR Gotcha" below for more details.
+.IP "DESTROY this" 4
+.IX Xref "DESTROY"
+.IX Item "DESTROY this"
+This method will be triggered when the tied variable needs to be destructed.
+As with other object classes, such a method is seldom necessary, because Perl
+deallocates its moribund object's memory for you automatically\-\-this isn't
+C++, you know. We'll use a DESTROY method here for debugging purposes only.
+.Sp
+.Vb 5
+\& sub DESTROY {
+\& my $self = shift;
+\& confess "wrong type" unless ref $self;
+\& carp "[ Nice::DESTROY pid $$self ]" if $Nice::DEBUG;
+\& }
+.Ve
+.PP
+That's about all there is to it. Actually, it's more than all there
+is to it, because we've done a few nice things here for the sake
+of completeness, robustness, and general aesthetics. Simpler
+TIESCALAR classes are certainly possible.
+.SS "Tying Arrays"
+.IX Xref "array, tying"
+.IX Subsection "Tying Arrays"
+A class implementing a tied ordinary array should define the following
+methods: TIEARRAY, FETCH, STORE, FETCHSIZE, STORESIZE, CLEAR
+and perhaps UNTIE and/or DESTROY.
+.PP
+FETCHSIZE and STORESIZE are used to provide \f(CW$#array\fR and
+equivalent \f(CWscalar(@array)\fR access.
+.PP
+The methods POP, PUSH, SHIFT, UNSHIFT, SPLICE, DELETE, and EXISTS are
+required if the perl operator with the corresponding (but lowercase) name
+is to operate on the tied array. The \fBTie::Array\fR class can be used as a
+base class to implement the first five of these in terms of the basic
+methods above. The default implementations of DELETE and EXISTS in
+\&\fBTie::Array\fR simply \f(CW\*(C`croak\*(C'\fR.
+.PP
+In addition EXTEND will be called when perl would have pre-extended
+allocation in a real array.
+.PP
+For this discussion, we'll implement an array whose elements are a fixed
+size at creation. If you try to create an element larger than the fixed
+size, you'll take an exception. For example:
+.PP
+.Vb 4
+\& use FixedElem_Array;
+\& tie @array, \*(AqFixedElem_Array\*(Aq, 3;
+\& $array[0] = \*(Aqcat\*(Aq; # ok.
+\& $array[1] = \*(Aqdogs\*(Aq; # exception, length(\*(Aqdogs\*(Aq) > 3.
+.Ve
+.PP
+The preamble code for the class is as follows:
+.PP
+.Vb 3
+\& package FixedElem_Array;
+\& use Carp;
+\& use strict;
+.Ve
+.IP "TIEARRAY classname, LIST" 4
+.IX Xref "TIEARRAY"
+.IX Item "TIEARRAY classname, LIST"
+This is the constructor for the class. That means it is expected to
+return a blessed reference through which the new array (probably an
+anonymous ARRAY ref) will be accessed.
+.Sp
+In our example, just to show you that you don't \fIreally\fR have to return an
+ARRAY reference, we'll choose a HASH reference to represent our object.
+A HASH works out well as a generic record type: the \f(CW\*(C`{ELEMSIZE}\*(C'\fR field will
+store the maximum element size allowed, and the \f(CW\*(C`{ARRAY}\*(C'\fR field will hold the
+true ARRAY ref. If someone outside the class tries to dereference the
+object returned (doubtless thinking it an ARRAY ref), they'll blow up.
+This just goes to show you that you should respect an object's privacy.
+.Sp
+.Vb 11
+\& sub TIEARRAY {
+\& my $class = shift;
+\& my $elemsize = shift;
+\& if ( @_ || $elemsize =~ /\eD/ ) {
+\& croak "usage: tie ARRAY, \*(Aq" . _\|_PACKAGE_\|_ . "\*(Aq, elem_size";
+\& }
+\& return bless {
+\& ELEMSIZE => $elemsize,
+\& ARRAY => [],
+\& }, $class;
+\& }
+.Ve
+.IP "FETCH this, index" 4
+.IX Xref "FETCH"
+.IX Item "FETCH this, index"
+This method will be triggered every time an individual element the tied array
+is accessed (read). It takes one argument beyond its self reference: the
+index whose value we're trying to fetch.
+.Sp
+.Vb 5
+\& sub FETCH {
+\& my $self = shift;
+\& my $index = shift;
+\& return $self\->{ARRAY}\->[$index];
+\& }
+.Ve
+.Sp
+If a negative array index is used to read from an array, the index
+will be translated to a positive one internally by calling FETCHSIZE
+before being passed to FETCH. You may disable this feature by
+assigning a true value to the variable \f(CW$NEGATIVE_INDICES\fR in the
+tied array class.
+.Sp
+As you may have noticed, the name of the FETCH method (et al.) is the same
+for all accesses, even though the constructors differ in names (TIESCALAR
+vs TIEARRAY). While in theory you could have the same class servicing
+several tied types, in practice this becomes cumbersome, and it's easiest
+to keep them at simply one tie type per class.
+.IP "STORE this, index, value" 4
+.IX Xref "STORE"
+.IX Item "STORE this, index, value"
+This method will be triggered every time an element in the tied array is set
+(written). It takes two arguments beyond its self reference: the index at
+which we're trying to store something and the value we're trying to put
+there.
+.Sp
+In our example, \f(CW\*(C`undef\*(C'\fR is really \f(CW\*(C`$self\->{ELEMSIZE}\*(C'\fR number of
+spaces so we have a little more work to do here:
+.Sp
+.Vb 11
+\& sub STORE {
+\& my $self = shift;
+\& my( $index, $value ) = @_;
+\& if ( length $value > $self\->{ELEMSIZE} ) {
+\& croak "length of $value is greater than $self\->{ELEMSIZE}";
+\& }
+\& # fill in the blanks
+\& $self\->STORESIZE( $index ) if $index > $self\->FETCHSIZE();
+\& # right justify to keep element size for smaller elements
+\& $self\->{ARRAY}\->[$index] = sprintf "%$self\->{ELEMSIZE}s", $value;
+\& }
+.Ve
+.Sp
+Negative indexes are treated the same as with FETCH.
+.IP "FETCHSIZE this" 4
+.IX Xref "FETCHSIZE"
+.IX Item "FETCHSIZE this"
+Returns the total number of items in the tied array associated with
+object \fIthis\fR. (Equivalent to \f(CWscalar(@array)\fR). For example:
+.Sp
+.Vb 4
+\& sub FETCHSIZE {
+\& my $self = shift;
+\& return scalar $self\->{ARRAY}\->@*;
+\& }
+.Ve
+.IP "STORESIZE this, count" 4
+.IX Xref "STORESIZE"
+.IX Item "STORESIZE this, count"
+Sets the total number of items in the tied array associated with
+object \fIthis\fR to be \fIcount\fR. If this makes the array larger then
+class's mapping of \f(CW\*(C`undef\*(C'\fR should be returned for new positions.
+If the array becomes smaller then entries beyond count should be
+deleted.
+.Sp
+In our example, 'undef' is really an element containing
+\&\f(CW\*(C`$self\->{ELEMSIZE}\*(C'\fR number of spaces. Observe:
+.Sp
+.Vb 10
+\& sub STORESIZE {
+\& my $self = shift;
+\& my $count = shift;
+\& if ( $count > $self\->FETCHSIZE() ) {
+\& foreach ( $count \- $self\->FETCHSIZE() .. $count ) {
+\& $self\->STORE( $_, \*(Aq\*(Aq );
+\& }
+\& } elsif ( $count < $self\->FETCHSIZE() ) {
+\& foreach ( 0 .. $self\->FETCHSIZE() \- $count \- 2 ) {
+\& $self\->POP();
+\& }
+\& }
+\& }
+.Ve
+.IP "EXTEND this, count" 4
+.IX Xref "EXTEND"
+.IX Item "EXTEND this, count"
+Informative call that array is likely to grow to have \fIcount\fR entries.
+Can be used to optimize allocation. This method need do nothing.
+.Sp
+In our example there is no reason to implement this method, so we leave
+it as a no-op. This method is only relevant to tied array implementations
+where there is the possibility of having the allocated size of the array
+be larger than is visible to a perl programmer inspecting the size of the
+array. Many tied array implementations will have no reason to implement it.
+.Sp
+.Vb 5
+\& sub EXTEND {
+\& my $self = shift;
+\& my $count = shift;
+\& # nothing to see here, move along.
+\& }
+.Ve
+.Sp
+\&\fBNOTE:\fR It is generally an error to make this equivalent to STORESIZE.
+Perl may from time to time call EXTEND without wanting to actually change
+the array size directly. Any tied array should function correctly if this
+method is a no-op, even if perhaps they might not be as efficient as they
+would if this method was implemented.
+.IP "EXISTS this, key" 4
+.IX Xref "EXISTS"
+.IX Item "EXISTS this, key"
+Verify that the element at index \fIkey\fR exists in the tied array \fIthis\fR.
+.Sp
+In our example, we will determine that if an element consists of
+\&\f(CW\*(C`$self\->{ELEMSIZE}\*(C'\fR spaces only, it does not exist:
+.Sp
+.Vb 7
+\& sub EXISTS {
+\& my $self = shift;
+\& my $index = shift;
+\& return 0 if ! defined $self\->{ARRAY}\->[$index] ||
+\& $self\->{ARRAY}\->[$index] eq \*(Aq \*(Aq x $self\->{ELEMSIZE};
+\& return 1;
+\& }
+.Ve
+.IP "DELETE this, key" 4
+.IX Xref "DELETE"
+.IX Item "DELETE this, key"
+Delete the element at index \fIkey\fR from the tied array \fIthis\fR.
+.Sp
+In our example, a deleted item is \f(CW\*(C`$self\->{ELEMSIZE}\*(C'\fR spaces:
+.Sp
+.Vb 5
+\& sub DELETE {
+\& my $self = shift;
+\& my $index = shift;
+\& return $self\->STORE( $index, \*(Aq\*(Aq );
+\& }
+.Ve
+.IP "CLEAR this" 4
+.IX Xref "CLEAR"
+.IX Item "CLEAR this"
+Clear (remove, delete, ...) all values from the tied array associated with
+object \fIthis\fR. For example:
+.Sp
+.Vb 4
+\& sub CLEAR {
+\& my $self = shift;
+\& return $self\->{ARRAY} = [];
+\& }
+.Ve
+.IP "PUSH this, LIST" 4
+.IX Xref "PUSH"
+.IX Item "PUSH this, LIST"
+Append elements of \fILIST\fR to the array. For example:
+.Sp
+.Vb 7
+\& sub PUSH {
+\& my $self = shift;
+\& my @list = @_;
+\& my $last = $self\->FETCHSIZE();
+\& $self\->STORE( $last + $_, $list[$_] ) foreach 0 .. $#list;
+\& return $self\->FETCHSIZE();
+\& }
+.Ve
+.IP "POP this" 4
+.IX Xref "POP"
+.IX Item "POP this"
+Remove last element of the array and return it. For example:
+.Sp
+.Vb 4
+\& sub POP {
+\& my $self = shift;
+\& return pop $self\->{ARRAY}\->@*;
+\& }
+.Ve
+.IP "SHIFT this" 4
+.IX Xref "SHIFT"
+.IX Item "SHIFT this"
+Remove the first element of the array (shifting other elements down)
+and return it. For example:
+.Sp
+.Vb 4
+\& sub SHIFT {
+\& my $self = shift;
+\& return shift $self\->{ARRAY}\->@*;
+\& }
+.Ve
+.IP "UNSHIFT this, LIST" 4
+.IX Xref "UNSHIFT"
+.IX Item "UNSHIFT this, LIST"
+Insert LIST elements at the beginning of the array, moving existing elements
+up to make room. For example:
+.Sp
+.Vb 9
+\& sub UNSHIFT {
+\& my $self = shift;
+\& my @list = @_;
+\& my $size = scalar( @list );
+\& # make room for our list
+\& $self\->{ARRAY}[ $size .. $self\->{ARRAY}\->$#* + $size ]\->@*
+\& = $self\->{ARRAY}\->@*
+\& $self\->STORE( $_, $list[$_] ) foreach 0 .. $#list;
+\& }
+.Ve
+.IP "SPLICE this, offset, length, LIST" 4
+.IX Xref "SPLICE"
+.IX Item "SPLICE this, offset, length, LIST"
+Perform the equivalent of \f(CW\*(C`splice\*(C'\fR on the array.
+.Sp
+\&\fIoffset\fR is optional and defaults to zero, negative values count back
+from the end of the array.
+.Sp
+\&\fIlength\fR is optional and defaults to rest of the array.
+.Sp
+\&\fILIST\fR may be empty.
+.Sp
+Returns a list of the original \fIlength\fR elements at \fIoffset\fR.
+.Sp
+In our example, we'll use a little shortcut if there is a \fILIST\fR:
+.Sp
+.Vb 11
+\& sub SPLICE {
+\& my $self = shift;
+\& my $offset = shift || 0;
+\& my $length = shift || $self\->FETCHSIZE() \- $offset;
+\& my @list = ();
+\& if ( @_ ) {
+\& tie @list, _\|_PACKAGE_\|_, $self\->{ELEMSIZE};
+\& @list = @_;
+\& }
+\& return splice $self\->{ARRAY}\->@*, $offset, $length, @list;
+\& }
+.Ve
+.IP "UNTIE this" 4
+.IX Xref "UNTIE"
+.IX Item "UNTIE this"
+Will be called when \f(CW\*(C`untie\*(C'\fR happens. (See "The \f(CW\*(C`untie\*(C'\fR Gotcha" below.)
+.IP "DESTROY this" 4
+.IX Xref "DESTROY"
+.IX Item "DESTROY this"
+This method will be triggered when the tied variable needs to be destructed.
+As with the scalar tie class, this is almost never needed in a
+language that does its own garbage collection, so this time we'll
+just leave it out.
+.SS "Tying Hashes"
+.IX Xref "hash, tying"
+.IX Subsection "Tying Hashes"
+Hashes were the first Perl data type to be tied (see \fBdbmopen()\fR). A class
+implementing a tied hash should define the following methods: TIEHASH is
+the constructor. FETCH and STORE access the key and value pairs. EXISTS
+reports whether a key is present in the hash, and DELETE deletes one.
+CLEAR empties the hash by deleting all the key and value pairs. FIRSTKEY
+and NEXTKEY implement the \fBkeys()\fR and \fBeach()\fR functions to iterate over all
+the keys. SCALAR is triggered when the tied hash is evaluated in scalar
+context, and in 5.28 onwards, by \f(CW\*(C`keys\*(C'\fR in boolean context. UNTIE is
+called when \f(CW\*(C`untie\*(C'\fR happens, and DESTROY is called when the tied variable
+is garbage collected.
+.PP
+If this seems like a lot, then feel free to inherit from merely the
+standard Tie::StdHash module for most of your methods, redefining only the
+interesting ones. See Tie::Hash for details.
+.PP
+Remember that Perl distinguishes between a key not existing in the hash,
+and the key existing in the hash but having a corresponding value of
+\&\f(CW\*(C`undef\*(C'\fR. The two possibilities can be tested with the \f(CWexists()\fR and
+\&\f(CWdefined()\fR functions.
+.PP
+Here's an example of a somewhat interesting tied hash class: it gives you
+a hash representing a particular user's dot files. You index into the hash
+with the name of the file (minus the dot) and you get back that dot file's
+contents. For example:
+.PP
+.Vb 8
+\& use DotFiles;
+\& tie %dot, \*(AqDotFiles\*(Aq;
+\& if ( $dot{profile} =~ /MANPATH/ ||
+\& $dot{login} =~ /MANPATH/ ||
+\& $dot{cshrc} =~ /MANPATH/ )
+\& {
+\& print "you seem to set your MANPATH\en";
+\& }
+.Ve
+.PP
+Or here's another sample of using our tied class:
+.PP
+.Vb 5
+\& tie %him, \*(AqDotFiles\*(Aq, \*(Aqdaemon\*(Aq;
+\& foreach $f ( keys %him ) {
+\& printf "daemon dot file %s is size %d\en",
+\& $f, length $him{$f};
+\& }
+.Ve
+.PP
+In our tied hash DotFiles example, we use a regular
+hash for the object containing several important
+fields, of which only the \f(CW\*(C`{LIST}\*(C'\fR field will be what the
+user thinks of as the real hash.
+.IP USER 5
+.IX Item "USER"
+whose dot files this object represents
+.IP HOME 5
+.IX Item "HOME"
+where those dot files live
+.IP CLOBBER 5
+.IX Item "CLOBBER"
+whether we should try to change or remove those dot files
+.IP LIST 5
+.IX Item "LIST"
+the hash of dot file names and content mappings
+.PP
+Here's the start of \fIDotfiles.pm\fR:
+.PP
+.Vb 5
+\& package DotFiles;
+\& use Carp;
+\& sub whowasi { (caller(1))[3] . \*(Aq()\*(Aq }
+\& my $DEBUG = 0;
+\& sub debug { $DEBUG = @_ ? shift : 1 }
+.Ve
+.PP
+For our example, we want to be able to emit debugging info to help in tracing
+during development. We keep also one convenience function around
+internally to help print out warnings; \fBwhowasi()\fR returns the function name
+that calls it.
+.PP
+Here are the methods for the DotFiles tied hash.
+.IP "TIEHASH classname, LIST" 4
+.IX Xref "TIEHASH"
+.IX Item "TIEHASH classname, LIST"
+This is the constructor for the class. That means it is expected to
+return a blessed reference through which the new object (probably but not
+necessarily an anonymous hash) will be accessed.
+.Sp
+Here's the constructor:
+.Sp
+.Vb 9
+\& sub TIEHASH {
+\& my $class = shift;
+\& my $user = shift || $>;
+\& my $dotdir = shift || \*(Aq\*(Aq;
+\& croak "usage: @{[&whowasi]} [USER [DOTDIR]]" if @_;
+\& $user = getpwuid($user) if $user =~ /^\ed+$/;
+\& my $dir = (getpwnam($user))[7]
+\& || croak "@{[&whowasi]}: no user $user";
+\& $dir .= "/$dotdir" if $dotdir;
+\&
+\& my $node = {
+\& USER => $user,
+\& HOME => $dir,
+\& LIST => {},
+\& CLOBBER => 0,
+\& };
+\&
+\& opendir(DIR, $dir)
+\& || croak "@{[&whowasi]}: can\*(Aqt opendir $dir: $!";
+\& foreach $dot ( grep /^\e./ && \-f "$dir/$_", readdir(DIR)) {
+\& $dot =~ s/^\e.//;
+\& $node\->{LIST}{$dot} = undef;
+\& }
+\& closedir DIR;
+\& return bless $node, $class;
+\& }
+.Ve
+.Sp
+It's probably worth mentioning that if you're going to filetest the
+return values out of a readdir, you'd better prepend the directory
+in question. Otherwise, because we didn't \fBchdir()\fR there, it would
+have been testing the wrong file.
+.IP "FETCH this, key" 4
+.IX Xref "FETCH"
+.IX Item "FETCH this, key"
+This method will be triggered every time an element in the tied hash is
+accessed (read). It takes one argument beyond its self reference: the key
+whose value we're trying to fetch.
+.Sp
+Here's the fetch for our DotFiles example.
+.Sp
+.Vb 6
+\& sub FETCH {
+\& carp &whowasi if $DEBUG;
+\& my $self = shift;
+\& my $dot = shift;
+\& my $dir = $self\->{HOME};
+\& my $file = "$dir/.$dot";
+\&
+\& unless (exists $self\->{LIST}\->{$dot} || \-f $file) {
+\& carp "@{[&whowasi]}: no $dot file" if $DEBUG;
+\& return undef;
+\& }
+\&
+\& if (defined $self\->{LIST}\->{$dot}) {
+\& return $self\->{LIST}\->{$dot};
+\& } else {
+\& return $self\->{LIST}\->{$dot} = \`cat $dir/.$dot\`;
+\& }
+\& }
+.Ve
+.Sp
+It was easy to write by having it call the Unix \fBcat\fR\|(1) command, but it
+would probably be more portable to open the file manually (and somewhat
+more efficient). Of course, because dot files are a Unixy concept, we're
+not that concerned.
+.IP "STORE this, key, value" 4
+.IX Xref "STORE"
+.IX Item "STORE this, key, value"
+This method will be triggered every time an element in the tied hash is set
+(written). It takes two arguments beyond its self reference: the index at
+which we're trying to store something, and the value we're trying to put
+there.
+.Sp
+Here in our DotFiles example, we'll be careful not to let
+them try to overwrite the file unless they've called the \fBclobber()\fR
+method on the original object reference returned by \fBtie()\fR.
+.Sp
+.Vb 7
+\& sub STORE {
+\& carp &whowasi if $DEBUG;
+\& my $self = shift;
+\& my $dot = shift;
+\& my $value = shift;
+\& my $file = $self\->{HOME} . "/.$dot";
+\& my $user = $self\->{USER};
+\&
+\& croak "@{[&whowasi]}: $file not clobberable"
+\& unless $self\->{CLOBBER};
+\&
+\& open(my $f, \*(Aq>\*(Aq, $file) || croak "can\*(Aqt open $file: $!";
+\& print $f $value;
+\& close($f);
+\& }
+.Ve
+.Sp
+If they wanted to clobber something, they might say:
+.Sp
+.Vb 3
+\& $ob = tie %daemon_dots, \*(Aqdaemon\*(Aq;
+\& $ob\->clobber(1);
+\& $daemon_dots{signature} = "A true daemon\en";
+.Ve
+.Sp
+Another way to lay hands on a reference to the underlying object is to
+use the \fBtied()\fR function, so they might alternately have set clobber
+using:
+.Sp
+.Vb 2
+\& tie %daemon_dots, \*(Aqdaemon\*(Aq;
+\& tied(%daemon_dots)\->clobber(1);
+.Ve
+.Sp
+The clobber method is simply:
+.Sp
+.Vb 4
+\& sub clobber {
+\& my $self = shift;
+\& $self\->{CLOBBER} = @_ ? shift : 1;
+\& }
+.Ve
+.IP "DELETE this, key" 4
+.IX Xref "DELETE"
+.IX Item "DELETE this, key"
+This method is triggered when we remove an element from the hash,
+typically by using the \fBdelete()\fR function. Again, we'll
+be careful to check whether they really want to clobber files.
+.Sp
+.Vb 2
+\& sub DELETE {
+\& carp &whowasi if $DEBUG;
+\&
+\& my $self = shift;
+\& my $dot = shift;
+\& my $file = $self\->{HOME} . "/.$dot";
+\& croak "@{[&whowasi]}: won\*(Aqt remove file $file"
+\& unless $self\->{CLOBBER};
+\& delete $self\->{LIST}\->{$dot};
+\& my $success = unlink($file);
+\& carp "@{[&whowasi]}: can\*(Aqt unlink $file: $!" unless $success;
+\& $success;
+\& }
+.Ve
+.Sp
+The value returned by DELETE becomes the return value of the call
+to \fBdelete()\fR. If you want to emulate the normal behavior of \fBdelete()\fR,
+you should return whatever FETCH would have returned for this key.
+In this example, we have chosen instead to return a value which tells
+the caller whether the file was successfully deleted.
+.IP "CLEAR this" 4
+.IX Xref "CLEAR"
+.IX Item "CLEAR this"
+This method is triggered when the whole hash is to be cleared, usually by
+assigning the empty list to it.
+.Sp
+In our example, that would remove all the user's dot files! It's such a
+dangerous thing that they'll have to set CLOBBER to something higher than
+1 to make it happen.
+.Sp
+.Vb 10
+\& sub CLEAR {
+\& carp &whowasi if $DEBUG;
+\& my $self = shift;
+\& croak "@{[&whowasi]}: won\*(Aqt remove all dot files for $self\->{USER}"
+\& unless $self\->{CLOBBER} > 1;
+\& my $dot;
+\& foreach $dot ( keys $self\->{LIST}\->%* ) {
+\& $self\->DELETE($dot);
+\& }
+\& }
+.Ve
+.IP "EXISTS this, key" 4
+.IX Xref "EXISTS"
+.IX Item "EXISTS this, key"
+This method is triggered when the user uses the \fBexists()\fR function
+on a particular hash. In our example, we'll look at the \f(CW\*(C`{LIST}\*(C'\fR
+hash element for this:
+.Sp
+.Vb 6
+\& sub EXISTS {
+\& carp &whowasi if $DEBUG;
+\& my $self = shift;
+\& my $dot = shift;
+\& return exists $self\->{LIST}\->{$dot};
+\& }
+.Ve
+.IP "FIRSTKEY this" 4
+.IX Xref "FIRSTKEY"
+.IX Item "FIRSTKEY this"
+This method will be triggered when the user is going
+to iterate through the hash, such as via a \fBkeys()\fR, \fBvalues()\fR, or \fBeach()\fR call.
+.Sp
+.Vb 6
+\& sub FIRSTKEY {
+\& carp &whowasi if $DEBUG;
+\& my $self = shift;
+\& my $a = keys $self\->{LIST}\->%*; # reset each() iterator
+\& each $self\->{LIST}\->%*
+\& }
+.Ve
+.Sp
+FIRSTKEY is always called in scalar context and it should just
+return the first key. \fBvalues()\fR, and \fBeach()\fR in list context,
+will call FETCH for the returned keys.
+.IP "NEXTKEY this, lastkey" 4
+.IX Xref "NEXTKEY"
+.IX Item "NEXTKEY this, lastkey"
+This method gets triggered during a \fBkeys()\fR, \fBvalues()\fR, or \fBeach()\fR iteration. It has a
+second argument which is the last key that had been accessed. This is
+useful if you're caring about ordering or calling the iterator from more
+than one sequence, or not really storing things in a hash anywhere.
+.Sp
+NEXTKEY is always called in scalar context and it should just
+return the next key. \fBvalues()\fR, and \fBeach()\fR in list context,
+will call FETCH for the returned keys.
+.Sp
+For our example, we're using a real hash so we'll do just the simple
+thing, but we'll have to go through the LIST field indirectly.
+.Sp
+.Vb 5
+\& sub NEXTKEY {
+\& carp &whowasi if $DEBUG;
+\& my $self = shift;
+\& return each $self\->{LIST}\->%*
+\& }
+.Ve
+.Sp
+If the object underlying your tied hash isn't a real hash and you don't have
+\&\f(CW\*(C`each\*(C'\fR available, then you should return \f(CW\*(C`undef\*(C'\fR or the empty list once you've
+reached the end of your list of keys. See \f(CW\*(C`each\*(Aqs own documentation\*(C'\fR
+for more details.
+.IP "SCALAR this" 4
+.IX Xref "SCALAR"
+.IX Item "SCALAR this"
+This is called when the hash is evaluated in scalar context, and in 5.28
+onwards, by \f(CW\*(C`keys\*(C'\fR in boolean context. In order to mimic the behaviour of
+untied hashes, this method must return a value which when used as boolean,
+indicates whether the tied hash is considered empty. If this method does
+not exist, perl will make some educated guesses and return true when
+the hash is inside an iteration. If this isn't the case, FIRSTKEY is
+called, and the result will be a false value if FIRSTKEY returns the empty
+list, true otherwise.
+.Sp
+However, you should \fBnot\fR blindly rely on perl always doing the right
+thing. Particularly, perl will mistakenly return true when you clear the
+hash by repeatedly calling DELETE until it is empty. You are therefore
+advised to supply your own SCALAR method when you want to be absolutely
+sure that your hash behaves nicely in scalar context.
+.Sp
+In our example we can just call \f(CW\*(C`scalar\*(C'\fR on the underlying hash
+referenced by \f(CW\*(C`$self\->{LIST}\*(C'\fR:
+.Sp
+.Vb 5
+\& sub SCALAR {
+\& carp &whowasi if $DEBUG;
+\& my $self = shift;
+\& return scalar $self\->{LIST}\->%*
+\& }
+.Ve
+.Sp
+NOTE: In perl 5.25 the behavior of scalar \f(CW%hash\fR on an untied hash changed
+to return the count of keys. Prior to this it returned a string containing
+information about the bucket setup of the hash. See
+"bucket_ratio" in Hash::Util for a backwards compatibility path.
+.IP "UNTIE this" 4
+.IX Xref "UNTIE"
+.IX Item "UNTIE this"
+This is called when \f(CW\*(C`untie\*(C'\fR occurs. See "The \f(CW\*(C`untie\*(C'\fR Gotcha" below.
+.IP "DESTROY this" 4
+.IX Xref "DESTROY"
+.IX Item "DESTROY this"
+This method is triggered when a tied hash is about to go out of
+scope. You don't really need it unless you're trying to add debugging
+or have auxiliary state to clean up. Here's a very simple function:
+.Sp
+.Vb 3
+\& sub DESTROY {
+\& carp &whowasi if $DEBUG;
+\& }
+.Ve
+.PP
+Note that functions such as \fBkeys()\fR and \fBvalues()\fR may return huge lists
+when used on large objects, like DBM files. You may prefer to use the
+\&\fBeach()\fR function to iterate over such. Example:
+.PP
+.Vb 7
+\& # print out history file offsets
+\& use NDBM_File;
+\& tie(%HIST, \*(AqNDBM_File\*(Aq, \*(Aq/usr/lib/news/history\*(Aq, 1, 0);
+\& while (($key,$val) = each %HIST) {
+\& print $key, \*(Aq = \*(Aq, unpack(\*(AqL\*(Aq,$val), "\en";
+\& }
+\& untie(%HIST);
+.Ve
+.SS "Tying FileHandles"
+.IX Xref "filehandle, tying"
+.IX Subsection "Tying FileHandles"
+This is partially implemented now.
+.PP
+A class implementing a tied filehandle should define the following
+methods: TIEHANDLE, at least one of PRINT, PRINTF, WRITE, READLINE, GETC,
+READ, and possibly CLOSE, UNTIE and DESTROY. The class can also provide: BINMODE,
+OPEN, EOF, FILENO, SEEK, TELL \- if the corresponding perl operators are
+used on the handle.
+.PP
+When STDERR is tied, its PRINT method will be called to issue warnings
+and error messages. This feature is temporarily disabled during the call,
+which means you can use \f(CWwarn()\fR inside PRINT without starting a recursive
+loop. And just like \f(CW\*(C`_\|_WARN_\|_\*(C'\fR and \f(CW\*(C`_\|_DIE_\|_\*(C'\fR handlers, STDERR's PRINT
+method may be called to report parser errors, so the caveats mentioned under
+"%SIG" in perlvar apply.
+.PP
+All of this is especially useful when perl is embedded in some other
+program, where output to STDOUT and STDERR may have to be redirected
+in some special way. See nvi and the Apache module for examples.
+.PP
+When tying a handle, the first argument to \f(CW\*(C`tie\*(C'\fR should begin with an
+asterisk. So, if you are tying STDOUT, use \f(CW*STDOUT\fR. If you have
+assigned it to a scalar variable, say \f(CW$handle\fR, use \f(CW*$handle\fR.
+\&\f(CW\*(C`tie $handle\*(C'\fR ties the scalar variable \f(CW$handle\fR, not the handle inside
+it.
+.PP
+In our example we're going to create a shouting handle.
+.PP
+.Vb 1
+\& package Shout;
+.Ve
+.IP "TIEHANDLE classname, LIST" 4
+.IX Xref "TIEHANDLE"
+.IX Item "TIEHANDLE classname, LIST"
+This is the constructor for the class. That means it is expected to
+return a blessed reference of some sort. The reference can be used to
+hold some internal information.
+.Sp
+.Vb 1
+\& sub TIEHANDLE { print "<shout>\en"; my $i; bless \e$i, shift }
+.Ve
+.IP "WRITE this, LIST" 4
+.IX Xref "WRITE"
+.IX Item "WRITE this, LIST"
+This method will be called when the handle is written to via the
+\&\f(CW\*(C`syswrite\*(C'\fR function.
+.Sp
+.Vb 5
+\& sub WRITE {
+\& $r = shift;
+\& my($buf,$len,$offset) = @_;
+\& print "WRITE called, \e$buf=$buf, \e$len=$len, \e$offset=$offset";
+\& }
+.Ve
+.IP "PRINT this, LIST" 4
+.IX Xref "PRINT"
+.IX Item "PRINT this, LIST"
+This method will be triggered every time the tied handle is printed to
+with the \f(CWprint()\fR or \f(CWsay()\fR functions. Beyond its self reference
+it also expects the list that was passed to the print function.
+.Sp
+.Vb 1
+\& sub PRINT { $r = shift; $$r++; print join($,,map(uc($_),@_)),$\e }
+.Ve
+.Sp
+\&\f(CWsay()\fR acts just like \f(CWprint()\fR except $\e will be localized to \f(CW\*(C`\en\*(C'\fR so
+you need do nothing special to handle \f(CWsay()\fR in \f(CWPRINT()\fR.
+.IP "PRINTF this, LIST" 4
+.IX Xref "PRINTF"
+.IX Item "PRINTF this, LIST"
+This method will be triggered every time the tied handle is printed to
+with the \f(CWprintf()\fR function.
+Beyond its self reference it also expects the format and list that was
+passed to the printf function.
+.Sp
+.Vb 5
+\& sub PRINTF {
+\& shift;
+\& my $fmt = shift;
+\& print sprintf($fmt, @_);
+\& }
+.Ve
+.IP "READ this, LIST" 4
+.IX Xref "READ"
+.IX Item "READ this, LIST"
+This method will be called when the handle is read from via the \f(CW\*(C`read\*(C'\fR
+or \f(CW\*(C`sysread\*(C'\fR functions.
+.Sp
+.Vb 8
+\& sub READ {
+\& my $self = shift;
+\& my $bufref = \e$_[0];
+\& my(undef,$len,$offset) = @_;
+\& print "READ called, \e$buf=$bufref, \e$len=$len, \e$offset=$offset";
+\& # add to $$bufref, set $len to number of characters read
+\& $len;
+\& }
+.Ve
+.IP "READLINE this" 4
+.IX Xref "READLINE"
+.IX Item "READLINE this"
+This method is called when the handle is read via \f(CW\*(C`<HANDLE>\*(C'\fR
+or \f(CW\*(C`readline HANDLE\*(C'\fR.
+.Sp
+As per \f(CW\*(C`readline\*(C'\fR, in scalar context it should return
+the next line, or \f(CW\*(C`undef\*(C'\fR for no more data. In list context it should
+return all remaining lines, or an empty list for no more data. The strings
+returned should include the input record separator \f(CW$/\fR (see perlvar),
+unless it is \f(CW\*(C`undef\*(C'\fR (which means "slurp" mode).
+.Sp
+.Vb 10
+\& sub READLINE {
+\& my $r = shift;
+\& if (wantarray) {
+\& return ("all remaining\en",
+\& "lines up\en",
+\& "to eof\en");
+\& } else {
+\& return "READLINE called " . ++$$r . " times\en";
+\& }
+\& }
+.Ve
+.IP "GETC this" 4
+.IX Xref "GETC"
+.IX Item "GETC this"
+This method will be called when the \f(CW\*(C`getc\*(C'\fR function is called.
+.Sp
+.Vb 1
+\& sub GETC { print "Don\*(Aqt GETC, Get Perl"; return "a"; }
+.Ve
+.IP "EOF this" 4
+.IX Xref "EOF"
+.IX Item "EOF this"
+This method will be called when the \f(CW\*(C`eof\*(C'\fR function is called.
+.Sp
+Starting with Perl 5.12, an additional integer parameter will be passed. It
+will be zero if \f(CW\*(C`eof\*(C'\fR is called without parameter; \f(CW1\fR if \f(CW\*(C`eof\*(C'\fR is given
+a filehandle as a parameter, e.g. \f(CWeof(FH)\fR; and \f(CW2\fR in the very special
+case that the tied filehandle is \f(CW\*(C`ARGV\*(C'\fR and \f(CW\*(C`eof\*(C'\fR is called with an empty
+parameter list, e.g. \f(CWeof()\fR.
+.Sp
+.Vb 1
+\& sub EOF { not length $stringbuf }
+.Ve
+.IP "CLOSE this" 4
+.IX Xref "CLOSE"
+.IX Item "CLOSE this"
+This method will be called when the handle is closed via the \f(CW\*(C`close\*(C'\fR
+function.
+.Sp
+.Vb 1
+\& sub CLOSE { print "CLOSE called.\en" }
+.Ve
+.IP "UNTIE this" 4
+.IX Xref "UNTIE"
+.IX Item "UNTIE this"
+As with the other types of ties, this method will be called when \f(CW\*(C`untie\*(C'\fR happens.
+It may be appropriate to "auto CLOSE" when this occurs. See
+"The \f(CW\*(C`untie\*(C'\fR Gotcha" below.
+.IP "DESTROY this" 4
+.IX Xref "DESTROY"
+.IX Item "DESTROY this"
+As with the other types of ties, this method will be called when the
+tied handle is about to be destroyed. This is useful for debugging and
+possibly cleaning up.
+.Sp
+.Vb 1
+\& sub DESTROY { print "</shout>\en" }
+.Ve
+.PP
+Here's how to use our little example:
+.PP
+.Vb 5
+\& tie(*FOO,\*(AqShout\*(Aq);
+\& print FOO "hello\en";
+\& $a = 4; $b = 6;
+\& print FOO $a, " plus ", $b, " equals ", $a + $b, "\en";
+\& print <FOO>;
+.Ve
+.SS "UNTIE this"
+.IX Xref "UNTIE"
+.IX Subsection "UNTIE this"
+You can define for all tie types an UNTIE method that will be called
+at \fBuntie()\fR. See "The \f(CW\*(C`untie\*(C'\fR Gotcha" below.
+.ie n .SS "The ""untie"" Gotcha"
+.el .SS "The \f(CWuntie\fP Gotcha"
+.IX Xref "untie"
+.IX Subsection "The untie Gotcha"
+If you intend making use of the object returned from either \fBtie()\fR or
+\&\fBtied()\fR, and if the tie's target class defines a destructor, there is a
+subtle gotcha you \fImust\fR guard against.
+.PP
+As setup, consider this (admittedly rather contrived) example of a
+tie; all it does is use a file to keep a log of the values assigned to
+a scalar.
+.PP
+.Vb 1
+\& package Remember;
+\&
+\& use v5.36;
+\& use IO::File;
+\&
+\& sub TIESCALAR {
+\& my $class = shift;
+\& my $filename = shift;
+\& my $handle = IO::File\->new( "> $filename" )
+\& or die "Cannot open $filename: $!\en";
+\&
+\& print $handle "The Start\en";
+\& bless {FH => $handle, Value => 0}, $class;
+\& }
+\&
+\& sub FETCH {
+\& my $self = shift;
+\& return $self\->{Value};
+\& }
+\&
+\& sub STORE {
+\& my $self = shift;
+\& my $value = shift;
+\& my $handle = $self\->{FH};
+\& print $handle "$value\en";
+\& $self\->{Value} = $value;
+\& }
+\&
+\& sub DESTROY {
+\& my $self = shift;
+\& my $handle = $self\->{FH};
+\& print $handle "The End\en";
+\& close $handle;
+\& }
+\&
+\& 1;
+.Ve
+.PP
+Here is an example that makes use of this tie:
+.PP
+.Vb 2
+\& use strict;
+\& use Remember;
+\&
+\& my $fred;
+\& tie $fred, \*(AqRemember\*(Aq, \*(Aqmyfile.txt\*(Aq;
+\& $fred = 1;
+\& $fred = 4;
+\& $fred = 5;
+\& untie $fred;
+\& system "cat myfile.txt";
+.Ve
+.PP
+This is the output when it is executed:
+.PP
+.Vb 5
+\& The Start
+\& 1
+\& 4
+\& 5
+\& The End
+.Ve
+.PP
+So far so good. Those of you who have been paying attention will have
+spotted that the tied object hasn't been used so far. So lets add an
+extra method to the Remember class to allow comments to be included in
+the file; say, something like this:
+.PP
+.Vb 6
+\& sub comment {
+\& my $self = shift;
+\& my $text = shift;
+\& my $handle = $self\->{FH};
+\& print $handle $text, "\en";
+\& }
+.Ve
+.PP
+And here is the previous example modified to use the \f(CW\*(C`comment\*(C'\fR method
+(which requires the tied object):
+.PP
+.Vb 2
+\& use strict;
+\& use Remember;
+\&
+\& my ($fred, $x);
+\& $x = tie $fred, \*(AqRemember\*(Aq, \*(Aqmyfile.txt\*(Aq;
+\& $fred = 1;
+\& $fred = 4;
+\& comment $x "changing...";
+\& $fred = 5;
+\& untie $fred;
+\& system "cat myfile.txt";
+.Ve
+.PP
+When this code is executed there is no output. Here's why:
+.PP
+When a variable is tied, it is associated with the object which is the
+return value of the TIESCALAR, TIEARRAY, or TIEHASH function. This
+object normally has only one reference, namely, the implicit reference
+from the tied variable. When \fBuntie()\fR is called, that reference is
+destroyed. Then, as in the first example above, the object's
+destructor (DESTROY) is called, which is normal for objects that have
+no more valid references; and thus the file is closed.
+.PP
+In the second example, however, we have stored another reference to
+the tied object in \f(CW$x\fR. That means that when \fBuntie()\fR gets called
+there will still be a valid reference to the object in existence, so
+the destructor is not called at that time, and thus the file is not
+closed. The reason there is no output is because the file buffers
+have not been flushed to disk.
+.PP
+Now that you know what the problem is, what can you do to avoid it?
+Prior to the introduction of the optional UNTIE method the only way
+was the good old \f(CW\*(C`\-w\*(C'\fR flag. Which will spot any instances where you call
+\&\fBuntie()\fR and there are still valid references to the tied object. If
+the second script above this near the top \f(CW\*(C`use warnings \*(Aquntie\*(Aq\*(C'\fR
+or was run with the \f(CW\*(C`\-w\*(C'\fR flag, Perl prints this
+warning message:
+.PP
+.Vb 1
+\& untie attempted while 1 inner references still exist
+.Ve
+.PP
+To get the script to work properly and silence the warning make sure
+there are no valid references to the tied object \fIbefore\fR \fBuntie()\fR is
+called:
+.PP
+.Vb 2
+\& undef $x;
+\& untie $fred;
+.Ve
+.PP
+Now that UNTIE exists the class designer can decide which parts of the
+class functionality are really associated with \f(CW\*(C`untie\*(C'\fR and which with
+the object being destroyed. What makes sense for a given class depends
+on whether the inner references are being kept so that non-tie-related
+methods can be called on the object. But in most cases it probably makes
+sense to move the functionality that would have been in DESTROY to the UNTIE
+method.
+.PP
+If the UNTIE method exists then the warning above does not occur. Instead the
+UNTIE method is passed the count of "extra" references and can issue its own
+warning if appropriate. e.g. to replicate the no UNTIE case this method can
+be used:
+.PP
+.Vb 6
+\& sub UNTIE
+\& {
+\& my ($obj,$count) = @_;
+\& carp "untie attempted while $count inner references still exist"
+\& if $count;
+\& }
+.Ve
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+See DB_File or Config for some interesting \fBtie()\fR implementations.
+A good starting point for many \fBtie()\fR implementations is with one of the
+modules Tie::Scalar, Tie::Array, Tie::Hash, or Tie::Handle.
+.SH BUGS
+.IX Header "BUGS"
+The normal return provided by \f(CWscalar(%hash)\fR is not
+available. What this means is that using \f(CW%tied_hash\fR in boolean
+context doesn't work right (currently this always tests false,
+regardless of whether the hash is empty or hash elements).
+[ This paragraph needs review in light of changes in 5.25 ]
+.PP
+Localizing tied arrays or hashes does not work. After exiting the
+scope the arrays or the hashes are not restored.
+.PP
+Counting the number of entries in a hash via \f(CW\*(C`scalar(keys(%hash))\*(C'\fR
+or \f(CWscalar(values(%hash)\fR) is inefficient since it needs to iterate
+through all the entries with FIRSTKEY/NEXTKEY.
+.PP
+Tied hash/array slices cause multiple FETCH/STORE pairs, there are no
+tie methods for slice operations.
+.PP
+You cannot easily tie a multilevel data structure (such as a hash of
+hashes) to a dbm file. The first problem is that all but GDBM and
+Berkeley DB have size limitations, but beyond that, you also have problems
+with how references are to be represented on disk. One
+module that does attempt to address this need is DBM::Deep. Check your
+nearest CPAN site as described in perlmodlib for source code. Note
+that despite its name, DBM::Deep does not use dbm. Another earlier attempt
+at solving the problem is MLDBM, which is also available on the CPAN, but
+which has some fairly serious limitations.
+.PP
+Tied filehandles are still incomplete. \fBsysopen()\fR, \fBtruncate()\fR,
+\&\fBflock()\fR, \fBfcntl()\fR, \fBstat()\fR and \-X can't currently be trapped.
+.SH AUTHOR
+.IX Header "AUTHOR"
+Tom Christiansen
+.PP
+TIEHANDLE by Sven Verdoolaege <\fIskimo@dns.ufsia.ac.be\fR> and Doug MacEachern <\fIdougm@osf.org\fR>
+.PP
+UNTIE by Nick Ing-Simmons <\fInick@ing\-simmons.net\fR>
+.PP
+SCALAR by Tassilo von Parseval <\fItassilo.von.parseval@rwth\-aachen.de\fR>
+.PP
+Tying Arrays by Casey West <\fIcasey@geeknest.com\fR>