[comp.lang.perl] Are only simple scalars allowed in "do SUBROUTINE

pem@frankland-river.aaii.oz.au (Paul E. Maisano) (03/04/90)

The manual section for "do SUBROUTINE (LIST)" says:
	SUBROUTINE may be a scalar variable, ... The parentheses are
	required to avoid confusion with the "do EXPR" form.

I always assumed that an array reference could be considered a scalar.
In particular I thought the following was allowed.

#!/usr/bin/perl
sub sub1 {print "1\n";}
sub sub2 {print "2\n";}
@subs = ('sub1', 'sub2');
do $subs[1]();

Unfortunately it gives a syntax error.

I think this is a pity. It is a useful thing to be able to do.
Allowing an arbitrary EXPR instead of a scalar would be even better :-)

Of course, we could always just use eval instead.
Not as elegant though (or as efficient, maybe).

------------------
Paul E. Maisano
Australian Artificial Intelligence Institute
1 Grattan St. Carlton, Vic. 3053, Australia
Ph: +613 663-7922  Fax: +613 663-7937
Email: pem@aaii.oz.au   UUCP: {uunet,mcsun,ukc,nttlab}!munnari!aaii.oz.au!pem

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (03/06/90)

In article <1211@frankland-river.aaii.oz.au> pem@frankland-river.aaii.oz.au (Paul E. Maisano) writes:
: The manual section for "do SUBROUTINE (LIST)" says:
: 	SUBROUTINE may be a scalar variable, ... The parentheses are
: 	required to avoid confusion with the "do EXPR" form.
: 
: I always assumed that an array reference could be considered a scalar.

A scalar value, but not a scalar variable.

: In particular I thought the following was allowed.
: 
: #!/usr/bin/perl
: sub sub1 {print "1\n";}
: sub sub2 {print "2\n";}
: @subs = ('sub1', 'sub2');
: do $subs[1]();
: 
: Unfortunately it gives a syntax error.
: 
: I think this is a pity. It is a useful thing to be able to do.
: Allowing an arbitrary EXPR instead of a scalar would be even better :-)

I might be able to get away with it in this part of the grammar, but
there are other similar parts of the grammar that I couldn't, and I
have to watch out for non-orthogonalities...

On top of which, there's the readability issue.

I also have people arguing for ('foo','bar')[$which].  Maybe.  I'm not
done thinking about it.  It's certainly more powerful to have [] and ()
as first class operators, but I'm not sure that such conciseness is
always a virtue.

: Of course, we could always just use eval instead.
: Not as elegant though (or as efficient, maybe).

More efficient than eval would be to use a temp variable:
    
    @subs = ('sub1', 'sub2','sub3','sub4');

    $whichsub = $subs[index($blather{$token},pack("c",$current_state))];
    do $whichsub(*my_stack);

I almost like that better than

    do $subs[index($blather{$token},pack("c",$current_state))](*my_stack);

There's something to be said for naming your intermediate products.

Larry

ccplumb@lion.waterloo.edu (Colin Plumb) (03/06/90)

In article <7269@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
> I also have people arguing for ('foo','bar')[$which].  Maybe.  I'm not
> done thinking about it.  It's certainly more powerful to have [] and ()
> as first class operators, but I'm not sure that such conciseness is
> always a virtue.

Well, when I wanted the time from a file, the first thing I tried was

$time = stat($file)[8];

It didn't work so well.  Then I looked for prolog-style "dummy" assignments,
as in (_,_,_,_,_,_,_,_,$time,_,_,_,_) = stat($file), and only after
failing in that did I create all those icky dummy variables to hold the
half of the stat array I don't care about.

Now that I think of it, 
$stat = stat($file);
$time = $stat[8];
might have been simpler...
-- 
	-Colin

merlyn@iwarp.intel.com (Randal Schwartz) (03/07/90)

In article <21611@watdragon.waterloo.edu>, ccplumb@lion (Colin Plumb) writes:
| Well, when I wanted the time from a file, the first thing I tried was
| 
| $time = stat($file)[8];
| 
| It didn't work so well.  Then I looked for prolog-style "dummy" assignments,
| as in (_,_,_,_,_,_,_,_,$time,_,_,_,_) = stat($file), and only after
| failing in that did I create all those icky dummy variables to hold the
| half of the stat array I don't care about.
| 
| Now that I think of it, 
| $stat = stat($file);
| $time = $stat[8];
| might have been simpler...

I've stumbled across wanting such a syntax as well.  I think it's the
C programmer in me that would think it natural.  I've held off asking
for it because I'm afraid it would break something.  Maybe in Perl 4? :-)

Also, Colin, those last two lines should be:

	@stat = stat($file);
	$time = $stat[8];

open(C,"|uncompress");$_=<<EOF;s/../pack('C',hex($&))/ge;print C $_;
1f9d904aeacca103228c9b3774d094910302ca423620d08419b366210b05
EOF
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (03/07/90)

In article <1990Mar6.180823.27618@iwarp.intel.com> merlyn@iwarp.intel.com (Randal Schwartz) writes:
: In article <21611@watdragon.waterloo.edu>, ccplumb@lion (Colin Plumb) writes:
: | Well, when I wanted the time from a file, the first thing I tried was
: | 
: | $time = stat($file)[8];
: | 
: | It didn't work so well.
: 
: I've stumbled across wanting such a syntax as well.  I think it's the
: C programmer in me that would think it natural.  I've held off asking
: for it because I'm afraid it would break something.  Maybe in Perl 4? :-)

It wouldn't be too hard except that

	EXPR [ EXPR ]

successfully parses $var[$foo], and it would be wrong.  It could probably
be worked out with some more shift-reduce ambiguities, but I'm loath.

Would you settle for this?

	( LIST ) [ EXPR ]

Since LISTs can contain anything that returns array values, you could say

	$time = (stat($file))[8];

That could be parsed unambiguously, methinks.

It would in fact be a slice operator, so you could say

	@days = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat')[$beg .. $end];

What think?

Larry

merlyn@iwarp.intel.com (Randal Schwartz) (03/07/90)

In article <7294@jpl-devvax.JPL.NASA.GOV>, lwall@jpl-devvax (Larry Wall) writes:
| 	( LIST ) [ EXPR ]
| 
| Since LISTs can contain anything that returns array values, you could say
| 
| 	$time = (stat($file))[8];
| 
| That could be parsed unambiguously, methinks.
| 
| It would in fact be a slice operator, so you could say
| 
| 	@days = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat')[$beg .. $end];
| 
| What think?

Yeah, yeah, yeah.  Supercool!  I'm thinking of how to use that in my
signatures already! :-)

print $_ x (($_ = "just another Perl hacker,") =~ s/j/J/);
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

tneff@bfmny0.UU.NET (Tom Neff) (03/07/90)

In article <7294@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
>Would you settle for this?
>
>	( LIST ) [ EXPR ]

Definitely, absolutely, this would be great!!

Slicing self-defining lists would be a subtle and powerful technique if
implemented.  And it's an elegant fit in the Perl model.

merlyn@iwarp.intel.com (Randal Schwartz) (03/08/90)

In article <15236@bfmny0.UU.NET>, tneff@bfmny0 (Tom Neff) writes:
| In article <7294@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
| >Would you settle for this?
| >
| >	( LIST ) [ EXPR ]
| 
| Definitely, absolutely, this would be great!!
| 
| Slicing self-defining lists would be a subtle and powerful technique if
| implemented.  And it's an elegant fit in the Perl model.

Yeah, and don't forget (since *I* forgot it :-),

	( LIST ) { EXPR }

for an assoc-array!  (Now, how's *that* for weird??!!)  Usage like:

	print ('r','red','b','blue','g','green'){$color}, " was picked.\n";

OK, so I'm a fanatic for orthogonality.  I dare'ya to parse that
cleanly.  Will it work inside quoted strings? :-) :-)

[I confess: I worked on the following sig ahead of time...]

open(M,"/usr/games/lib/quiz.k/morse") || die "morse: ($!)";
while(<M>) {next unless /([A-Z]):(.*)/; $m{$2}=$1;} close(M);
print grep($_ = ($m{$_} || $_), split(/([^-.])/,<<EOF)); exit 0;
.--- ..- ... -/.- -. --- - .... . .-./.--. . .-. .-../.... .- -.-. -.- . .-.,
EOF
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (03/08/90)

In article <15236@bfmny0.UU.NET> tneff@bfmny0.UU.NET (Tom Neff) writes:
: In article <7294@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
: >Would you settle for this?
: >
: >	( LIST ) [ EXPR ]
: 
: Definitely, absolutely, this would be great!!
: 
: Slicing self-defining lists would be a subtle and powerful technique if
: implemented.  And it's an elegant fit in the Perl model.

It's already implemented, and will be in patch 13.  Wasn't too hard--just
had to get the do_slice() routine to allow the stack as a valid array
to fetch things from.

An interesting side effect of this is that negative subscripts refer to
items farther down the stack.  I'm not going to document this, but I've
made (LIST)[-1] (assuming $[ is 0) be the size of the stack underneath
(LIST)[-1], so (LIST)[-2] is the top of the stack before this expression
started being evaluated.  Might turn out handy for some debugging
applications.  If you write a script depending on this, we will deny
your existence...

I'm also doing the other array operator we talked about as follows

	splice(@array,$offset,$length,LIST);

It always chops the elements mentioned out the array and returns them.
It then replaces those elements with the elements of LIST, which can
of course be a null list.  The following equivalencies hold:

	pop(@array)		splice(@array,-1,1)
	shift(@array)		splice(@array,0,1)
	push(@array,$x,$y)	splice(@array,$#array+1,0,$x,$y)
	unshift(@array,$x,$y)	splice(@array,0,0,$x,$y)

Implementation-wise, this will be the same as assigning to substr()--if
you insert a LIST the same size as the one you delete, nothing has to
be moved.  If you shrink it, it moves the minimal number of pointers
to satisfy it.  If you grow it, it tries to do the same, but it might
have to realloc the whole shmear.  Such is life.

I thought "splice" was the absolutely perfect name for this.  I had
considered doing

	splice(@array,$offset,$length) = ($x,$y)

but if I did that I'd either have to not return the old value
consistently, or I'd have to violate the rule that assignment always
returns the new value of a thing.  Besides, lvalues are hard.
So splice syntax just turns out to be a variant of push.  I didn't
even have to add to the grammar for it..

Larry