[Chapter 3] 3.2 Typeglobs
Author: Sriram Srinivasan
Date: 1999-07-02T01:31:23Z

#

| Chapter 3 Typeglobs and Symbol Tables |

## 3.2 Typeglobs

Typeglobs, we mentioned earlier, can be localized (with `local` only) and assigned to one another. Assigning a typeglob has the effect of aliasing one identifier name to another. Consider

    $spud   = "Wow!";
    @spud   = ("idaho", "russet");
    *potato = *spud;   # Alias potato to spud using typeglob assignment
    print "$potato\n"; # prints "Wow!"
    print @potato, "\n"; # prints "idaho russet"

Once the typeglob assignment is made, all entities that were called "spud" can now also be referred to as "potato" - the names are freely interchangeable. That is, `$spud` and `$potato` are the same thing, and so are the subroutines `&spud` and `&potato`. Figure 3.2 shows the picture after a typeglob assignment; both entries in the symbol table end up pointing to the same typeglob value.[3]

> [3] There is a wee bit of simplification here, which we will clarify in Chapter 20.

#### Figure 3.2: Assigning *spud to *potato: both symbol table entries point to the same typeglob

The alias holds true until the typeglob is reassigned or removed. (We will shortly see how to remove a typeglob.) In the example, there is no subroutine called `spud`, but if we define it after the typeglobs have been assigned, that subroutine can also be invoked as `potato`. It turns out that the alias works the other way too. If you assign a new list to `@potato`, it will also be automatically accessible as `@spud`.

### 3.2.1 Temporary Aliases

For now, there is no easy, intuitive way to get rid of an alias created by a typeglob assignment (you may reassign it, of course). You can, however, get temporary aliases using `local`, because it restores the typeglob's values at the end of the block.

Consider

    $b = 10;
    {
        local *b;    # Save *b's values
        *b = *a;     # Alias b to a
        $b = 20;     # Same as modifying $a instead
    }                # *b restored at end of block
    print $a;        # prints "20"
    print $b;        # prints "10"

`local` `*b` localizes all changes to variables named "`b`"; that is, it puts all of `*b`'s value pointers into safekeeping and substitutes an `undef` value for all of them. This lasts until the end of the block, whereupon the previous values of everything named "`b`" are restored (`$b` becomes 10 again). Now, because of the alias (`*b` `=` `*a`), the assignment `$b` `=` `20` has the effect of modifying both `$a` and `$b`. But at the end of the block, only `$b` is restored, and `$a` is left with the new value.

While we are on the subject, it is important to recall that lexical variables and the symbol table have nothing to do with each other; for this reason, localizing a typeglob with `my` is a compile-time error:

    my(*F);

The script dies with this error: "Can't declare ref-to-glob cast in my."

### 3.2.2 Using Typeglob Aliases

This section discusses a number of places where typeglob aliases work very well.

#### 3.2.2.1 Efficient parameter passing

Aliases happen to be quite a bit faster than references, because they don't need to do any dereferencing. Consider

    $a = 10;
    *b = *a ; $b++ ;  # 1. Increment $a indirectly through the typeglob
    $r = \$a; $$r++;  # 2. Increment $a indirectly through the reference

Case 1 is around one and a half times faster than case 2 on my PC.

The example code below uses typeglobs to efficiently pass an array by reference to a subroutine, `DoubleEachEntry`, which doubles each element of the array:

    @array = (10,20);
    DoubleEachEntry(*array); # @array and @copy are identical.
    print "@array \n"; # prints 20 40

    sub DoubleEachEntry {
        # $_[0] contains *array
        local *copy = shift;  # Create a local alias
        foreach $element (@copy) {
            $element *= 2;
        }
    }

Note that only one parameter is passed to the subroutine. The typeglob `*copy` springs into existence when it is first encountered, but because it didn't exist prior to the `local` statement, it and the corresponding entry in the symbol table are removed at the end of the block.

Incidentally, the code also takes advantage of the fact that the `foreach` statement internally aliases each successive element of `@copy` to `$element`, so modifying `$element` affects the elements of `@copy` (and therefore `@array` as well).

You cannot use a lexically scoped array as a parameter to `DoubleEachEntry`, because lexical variables don't have typeglobs associated with them. The restriction is easily circumvented, however. Typeglobs and references are strangely equivalent, as it turns out. You can pass in an ordinary reference to a subroutine expecting a typeglob, and it'll work well. (We'll have a little more to say about this in the section "Typeglobs and References.") That is, you can pass lexically scoped arrays to `DoubleEachEntry` like this:

    my @array  = (1, 2, 3);
    DoubleEachEntry(\@array); # Instead of *array, which wouldn't work

#### 3.2.2.2 Aliasing on command lines

I often embed the Perl interpreter in my C/C++ programs to provide a powerful shell-like frontend. While I like to use long and descriptive subroutine names in Perl scripts, it is painful to keep typing them on the frontend's prompt. Aliases are very useful here:

    sub a_long_drawn_out_sub_name {
       print "A sub by any other name is still a sub \n";
    }
    *f = *a_long_drawn_out_sub_name; # create an alias

Now typing `f()` on the command line is the same as calling the original subroutine but much easier on the carpals!

#### 3.2.2.3 Friendly predefined variables with aliases

Consider the opposite case. Perl has a number of cryptic built-in variables such as `$!`, `$/`, and `$@` , and many people would much rather work with longer descriptive names. The module English.pm in the standard Perl library comes to the rescue; it provides nice big, long aliased names, such as `$ERRNO`, `$INPUT_RECORD_SEPARATOR`, and `$EVAL_ERROR` (respectively). Try this:

    use English;    # Import the module file called English.pm
    # Try deleting a non-existent file
    unlink ('/tmp/foo');
    if ($ERRNO)  {  # Use $ERRNO instead of $!
        print $ERRNO, "\n"; # Prints "No such file or directory"
    }

(We'll cover packages and the `use` statement in Chapter 6.) I think these well-known names should have been in there from the very beginning, instead of having to memorize funny-looking variables and an accompanying list of mnemonics. Some argue that you can use the same scheme for other languages ("`use` `Dutch;`"), but considering that the other system calls are in English anyway, I think that there's no point providing specific aliases for a small subset of the things you have to remember.

### 3.2.3 Aliasing Problem: Variable Suicide

Aliases, combined with the fact that `local` doesn't really create new variables (it temporarily slaps a new value onto a global variable), often leads to weird values of variables that presumably haven't even been touched. Consider the following simple case:

    $x = 10;
    foo(*x);
    sub foo {
        local(*y) = @_;
        print "Before value of y : $y \n";
        local($x) = 100;
        print "After value of y : $y \n";
    }

This prints the following:

    Before value of y : 10
    After value of y : 100

Can you resolve the mystery? Clearly, `$y` has not been touched between the two `print` statements, but its value seems to have changed. Hint: it reflects that of `$x`.

Let's trace the events in sequence:

    $x = 10;                  # Assign a value to global $x
                              # function called
    local *y = *x;            # Save global *y's values. Alias it to *x
    print "before value"      # Because of the alias, $y is the same as $x,
                              # hence this prints 10
    local $x = 100;           # IMPORTANT: local saves $x's value (10)
                              # and substitutes 100. Note that it does not
                              # create a new $x variable
                              # replaced by 100
    print "after value";      # But *y is still aliased to *x. Therefore,
                              # $y now contains 100

The interaction of aliases and `local` can be even more subtle. Consider

    foreach $f (10, 20, 30) {
        foo (*f);
    }
    sub foo {
        local (*g) = @_;
        $g++;
    }

This prints the error: "Modification of a read-only value attempted at try.pl line 6."

The sequence is as follows: For efficiency, the `foreach` operator aliases `$f` to the next element of the list in every iteration, each of which is a constant. The subroutine `foo` aliases `*g` to `*f`, which means that `$g` is aliased to a constant. For this reason, the operation `$g++` causes a problem.

Moral of the story: if you want truly local variables, use `my`. Use typeglob aliasing and `local` sparingly.

3.1 Perl Variables, Symbol Table, and Scoping |  | 3.3 Typeglobs and References