From: tchrist@convex.COM (Tom Christiansen)
Newsgroups: comp.lang.perl
Subject: Re: question of building array of arrays
Date: 2 Oct 92 13:00:55 GMT
Reply-To: tchrist@convex.COM (Tom Christiansen)
Organization: Convex Computer Corporation, Colorado Springs, CO
Originator: tchrist@pixel.convex.com
X-Disclaimer: This message was written by a user at CONVEX Computer
              Corp. The opinions expressed are those of the user and
              not necessarily those of CONVEX.

From the keyboard of kc@hpscit.sc.hp.com (Kwok Cheung):
:	Thank you AJS for answering the questions, I try his
:code, it did what I want to do. But I have a question about one line
:of his code. The code works, I just want to understanding the syntex.
:
:foreach(@food)
:{
:       *array = @_;  # <<<<<<<< this line
:       print "Food of class \"$_\":\n\t", join(', ',@array), "\n";
:}
:
:	Apparently, this assign the LIST @food to @array. 

No, that's not quite it.  It makes *array a temporary aliases for each
element in $food.  It's more kosher in proper perl etiquette to have a
pointer on both sides of the equation, but there's an automatic coercion
happening such that

    *a = 'blah';

is magically interpreted to mean

    *a = *blah;

:
:     *array = @_;
: 
:	When I run it,  it output 
:
:Food of class "fruit":
:
:Food of class "meat":
:
:Food of class "vegetable":
:
:instead of 
:
:Food of class "fruit":
:        orange, apple
:Food of class "meat":
:        pork, beef
:Food of class "vegetable":
:        cabbage, lettice
:
:	I don't understand the different of $_ and @_ , Would somebody explain?

What's wrong is that that code is wrong.  @_ is most typically the
subroutine parameters.  It too is highly magical, in that it contains
aliases for its callers scalar values.  This, for example, makes sense

    &func(*a, *b, *c);

and following what I said before:

    &func(a, b, c);
    &func('a', 'b', 'c');

but compare:

    &func2('a', 'b', 'c');
    &func2(a, b, c);

when you examine the subroutines:

    sub func {
	local(*x, *y, *z) = @_;
	...
    } 

    sub func2 {
	local($x, $y, $z) = @_;
	...
    } 


So, @_ is the subroutine args.  $_, on the other hand, is
entirely unrelated.  It is the default variable in a whole
bunch of different operations, including the for loop:

    for (*a, *b, *c) {
	*x = $_;
    } 

would work fine.


:Another question I have is:
:
:Can we assign a LIST to an associative array
:        %day = ( 'weekday', 'Monday,Tuesday,Wedneday,Thurday,Friday' 
:                 'weekend', 'Saturday,Sunday' 
:               );
:and use the foreach loop to access the member of the LIST

You can do what you just did, but that's not what you said you did.
The key must be a scalar value, not a list.

    for $kind ('weekday', 'weekend') {
	@days = split(',', $day{$kind});
	for $day (@days) {
	    print "$day is a $kind\n";
	} 
    } 

Notice you have to split it.  You could also assign a pointer (itself
a scalar value) to do this:

    @weekday = ( Monday, Tuesday, Wedneday, Thurday, Friday );
    @weekend  = ( Saturday, Sunday );

    %day = {
	'weekday',	*weekday,
	'weekend',	*weekend,
    }; # sometimes i wish this semicolon would go away 

    for $kind (keys %days) {
	*list = $days{$kind};  # DON'T ASSIGN to *days!!!
	for $day (@list) {
	    print "$day is a $kind\n";
	} 
    } 

That's now.  Let's talk about making this better...

It seems likely that what you want is something like this:

    %day = (
	'weekday', ( Monday, Tuesday, Wedneday, Thurday, Friday ),
	'weekend', ( Saturday, Sunday ),
    }; # sometimes i wish this semicolon would go away 

but you can't do that.  In perl5, you'll likely be able to do this;
the [a,b,c] notation is a (typed) reference to (a,b,c).

    %day = (
	'weekday', [ Monday, Tuesday, Wedneday, Thurday, Friday ],
	'weekend', [ Saturday, Sunday ],
    }; # sometimes i wish this semicolon would go away 

    foreach $type ('weekday', 'weekend') {
	foreach $day ( @{$day{$kind}} ) {
	    print $day is $type\n"
	} 
    }

or maybe

    foreach $type ('weekday', 'weekend') {
	\@days =  $day{$kind};
	foreach $day ( @days ) {
	    print $day is $type\n"
	}
    }

Although it does start to get a bit ugly when you say

    ${$day{'weekday'}}[2];

which may not quite be the right future syntax, but is close
enough to give you an idea.


--tom
-- 
    Tom Christiansen      tchrist@convex.com      convex!tchrist

    Though I'll admit readability suffers slightly... 
                    --Larry Wall in <2969@jato.Jpl.Nasa.Gov>
Newsgroups: comp.lang.perl