hsmyers has asked for the wisdom of the Perl Monks concerning the following question:
I've lately been playing around with the IO:: modules, File,
Scalar and ScalarArray. I've noticed some behavior that leaves
me a little puzzled- the old feature versus bug thing. Here's
what I'm talking about, starting with filehandles. No matter
which style you use, open FILE, name or $fh =
IO::File->new(name), old and new styles are pretty much
transparent, i.e. code written one way can be changed to the
other with minimal bother. There is one thing though, this:
#!/perl/bin/perl
#
# test.pl -- IO:: test code...
use strict;
use warnings;
use diagnostics;
use IO::ScalarArray;
use IO::File;
use IO::Scalar;
my @list = qw(one.tmp two.tmp three.tmp);
my @handles;
foreach (@list) {
push @handles,new IO::File ">$_";
}
for (my $i = 0;$i < $#handles ;$i++) {
print $handles[$i] ,"Hi how the hell are ya!";
close $handles[$i];
}
doesn't work worth a damn. You get an error message like:
String found where operator expected at test.pl line 31, near "] "Hi h
+ow the
hell are ya!"" (#1)
(S) The Perl lexer knows whether to expect a term or an operator.
+ If it
sees what it knows to be a term when it was expecting to see an
operator, it gives you this warning. Usually it indicates that an
operator or delimiter was omitted, such as a semicolon.
(Missing operator before "Hi how the hell are ya!"?)
syntax error at test.pl line 31, near "] "Hi how the hell are ya!""
Execution of test.pl aborted due to compilation errors (#2)
Uncaught exception from user code:
syntax error at test.pl line 31, near "] "Hi how the hell are
+ya!""
Execution of test.pl aborted due to compilation errors.
C:\Perl\Perl_Dev\regex>perl test.pl
Undefined subroutine &main::mprint called at test.pl line 31 (#1)
(F) The subroutine indicated hasn't been defined, or if it was, it
+ has
since been undefined.
Uncaught exception from user code:
Undefined subroutine &main::mprint called at test.pl line 31.
It doesn't work any better on similar code using old style
typeglobs:
open ONE, ">one.tmp";
push @handles, *ONE;
open TWO, ">two.tmp";
push @handles, *TWO;
open THREE, ">three.tmp";
push @handles, *THREE;
Dies in the same place and manner. The code works just fine
if you create a temporary simple scalar with a copy of the
contents of the array position. Like '$fh = $handles[$i]; print
$fh yadda, yadda, yadda'. So somehow perl doesn't evaluate
'array position containing scalar' to 'scalar contained'. Which
last, is certainly what I had expected. Note that any reduction
to simple scalar works fine.
Another peculiarity, lies in the difference between
filehandles created by IO::File versus IO::Scalar and
IO::ScalarArray. Simply put, in the first case $fh =
IO::File->new whatever, <$fh> works fine, pretty much
keeping up the aforementioned transparency. But, if $fh comes
from either IO::Scalar or IO::ScalarArray, the shorthand,
<$fh>, dies the usual nasty death.
The work-around is to use either $fh->getline() or
$fh->getlines() as needed (wantarray versus scalar context.)
Since both inherit from IO::Handles and since the source for
handle.pm suggests that:
"The getline method returns a single line from the
filehandle, just like the <$fh> operator when used in a
scalar context. the getlines method returns a list of lines
in a manner identical to the <$fh> operator in a list
context. The getlines method will croak if called in a scalar
context."
Note that it doesn't say <$fh> for IO::Scalar and
IO::ScalarArray dies...just says this stuff about 'just like
the <$fh>...'.
It occurs to me that these two things are just different
sides of the same coin. For whatever reason, perl does not
evaluate the thing in question as a filehandle and complains
accordingly.
So having said all of this, would someone point out to me
what I've gotten wrong, misunderstood or the like. I am
entirely too aware of my own blind spots, particularly when
things don't appear to work as I had expected (that shouldn't
be too surprising, great expectations are usually replaced by
reality sooner or later…).
hsm
Re: Real World 1, Great Expectations 0
by wog (Curate) on Oct 18, 2001 at 03:56 UTC
|
Your error message indicates that you had
print $handles[$i] "Hi how the hell are ya!";,
not what you copied here, so I am going to assume that
is what you meant to copy. (And copying-and-pasting in
the future will prevent transcription mistakes like this.)
Your problem is caused by an odd ambiguity of the
"indirect object" syntax that print uses.
That is, when you say:
something $array[$i]
would it mean
something {$array} [$i]
or
something {$array[$i]}
(where the {} can be used to set off
the actual "object" you want to act on)?
To resolve this ambiguity
without incuring too much lookahead, perl treats it like:
something {$array} [$i]
You do have arguments after it, so concievably perl could
disambiguite:
something $array[$i] $something_else
into:
something {$array[$i]} $something_else
but it doesn't try to look that far ahead, it just
treats it like:
something {$array} [$i] $something_else
which is a syntax error because it has no comma
(update: after the [$i])
Thus, there are two ways to make
that take $handles[$i] be the first argument:
-
Use {}s: print {$handles[$i]} "...";
-
Use the IO::Handle module and use the -> syntax: use IO::Handle; $handles[$i]->print("...");
update: see also perlobj which discusses
this ambiguity under the heading "WARNING".
(update: minor grammatical edit(s) above) | [reply] [d/l] [select] |
|
Yes! and the winner is… Thank you for precisely the information I was looking for. I had tried something like your first answer, but the perldoc said parens or plus sign, not curley braces (what are they called anyway?), so I didn't get far. As for answer #2, certainly this works (although as I said, I hadn't gotten around to IO::Handle yet) but then so do a lot of other techniques as well. What I was looking for was what you explained— why it didn't work, not workarounds. Thanks again,hsm
| [reply] |
|
...not curley braces (what are they called anyway?)
I seem to remember reading this in a previous life:
    () are braces
    {} are brackets
Update: I stand corrected. See pjf's response below.
mr greywolf
| [reply] |
|
Re: Real World 1, Great Expectations 0
by tadman (Prior) on Oct 18, 2001 at 02:57 UTC
|
| [reply] [d/l] |
|
A few things... First I'm not using IO::Handle, second, I'm fully aware of a variety of workarounds— that is not the point, the question is why the syntax used doesn't work! A question that was well answered in a later reply. Now for the good news, I hadn't gotten around to using IO::Handle, your comments suggest I should investigate post haste, and I will. Thankshsm
| [reply] |
|
IO::File inherits from IO::Handle, so the parent methods are also available to you. (You might have better luck with the ambiguous syntax if you use a Perl-style loop. I have not tested that, however.)
Update: PSI::ESP will only be available when the already-complex Perl grammar is complete enough to DWIMHM (might have meant). :)
Anyone who can figure out how to allow post-expression for clauses while retaining the standard procedural loop and adding support for finding missing semicolons in the first case, should feel free to send me a message. We could fix a parser bug. *shiver*
| [reply] |
|
|
Yeah well, so I'm not using it directly, IO::Handle that is. Insert sheepish grin here[ ____ ]. In defense of self, this whole exercise arose from someone else's code—which same I reduced to a test case, so that we could look at the array reference problem. In real life, I don't mix approaches like that— no really I don't. Nope, not me, my evil twin (who fires from the hip enough to get hip burns) might, but no, not me!hsmp.s. thanks again...
| [reply] |
Re: Real World 1, Great Expectations 0
by premchai21 (Curate) on Oct 18, 2001 at 02:34 UTC
|
A style tip: use foreach instead of for. Also, you have an extraneous comma before the string.
foreach (@handles)
{
print $_ "Blah blah blah\n";
close $_;
}
| [reply] [d/l] |
|
Thanks for the tip...however, that has nothing to do with the problem I am illustrating. As I said any technique (and there are a whole host of them) that reduces the reference to a simple scalar makes the problem go away. Work arounds are of course our friend, but that still doesn't explain why what should work doesn't. See prize winning answer below... Thankshsm
| [reply] |
|
|