Return from function into a <> operator

P

PerlUser

Hello,
Please give me an idea of how the following scenario can work. I am
use to C reference / dereference concepts, but after reading perlref
half a dozen times and looking at dozens of newsgroups, I have not been
able to come up with a solution. Given the following code and a file
called "out" with a few lines of junk;
====================
sub tst {
open($FID, "<out");
printf("FID in sub = $FID\n");
return($FID);
}

# Works
$FID = tst();
while (<$FID>) { printf("REC=$_");}
close($FID);

# Works
$FID = *{&tst()}{GLOB};
while (<$FID>) { printf("REC=$_");}
close($FID);

# Works
sysread(tst(), $REC, 100);
printf("REC=${REC}\n");
close($FID);
====================
What I would like is to avoid the assignment of $FID and put the
function call directly into the while loop using the <> operator.
Basically:
while (<tst()>) { printf("REC=$_");}

I know there is a simple solution to this (a few characters on one side
or the other of tst()), but I have yet been able to find the smoking
gun. I am avoiding using any other packages (e.g. no "use" commands...
just built-in functionality).

Thank you in advance for your responses.

v5.8.0 built for i386-linux-thread-multi
 
B

Brian McCauley

PerlUser said:
Hello,
Please give me an idea of how the following scenario can work. I am
use to C reference / dereference concepts, but after reading perlref
half a dozen times and looking at dozens of newsgroups, I have not been
able to come up with a solution. Given the following code and a file
called "out" with a few lines of junk;
====================
sub tst {
open($FID, "<out");

You forgot to declare $PID. The $FID being modified inside &tst is
therefore the $FID from the enclosing scope.

Make that:

open(my $FID, '<', 'out') or die $!;
printf("FID in sub = $FID\n");

You apper to be confusing printf() and print().
return($FID);
}

# Works
$FID = tst();
while (<$FID>) { printf("REC=$_");}
close($FID);
What I would like is to avoid the assignment of $FID and put the
function call directly into the while loop using the <> operator.
Basically:
while (<tst()>) { printf("REC=$_");}

I know there is a simple solution to this (a few characters on one side
or the other of tst()),

Are you sure?
but I have yet been able to find the smoking gun.

See the documentation of the <...> syntax in perlop.

The <...> is in fact a shorthand for two compley different things.

<$FID> is short for readline($FID)

<tst()> is short for glob('tst()')

The exact rules are in the documentation but in all but the simplest
case I would simply write glob() or readline() longhand.

However there is another problem:

while (readline(tst())) { printf("REC=$_");}

Puts the call to tst() inside the loop so you just get the first line
over and over.
 
A

attn.steven.kuo

PerlUser said:
Hello,
Please give me an idea of how the following scenario can work. I am
use to C reference / dereference concepts, but after reading perlref
half a dozen times and looking at dozens of newsgroups, I have not been
able to come up with a solution. Given the following code and a file
called "out" with a few lines of junk;
====================
sub tst {
open($FID, "<out");
printf("FID in sub = $FID\n");
return($FID);
}

# Works
$FID = tst();
while (<$FID>) { printf("REC=$_");}
close($FID);

(snipped ...)
What I would like is to avoid the assignment of $FID and put the
function call directly into the while loop using the <> operator.
Basically:
while (<tst()>) { printf("REC=$_");}

I know there is a simple solution to this (a few characters on one side
or the other of tst()), but I have yet been able to find the smoking
gun. I am avoiding using any other packages (e.g. no "use" commands...
just built-in functionality).


My understanding from reading the documentation
(e.g., perlop) is that one cannot have a function call
between angle bracket to mean readline.

An excerpt:

If what's within the angle brackets is neither a filehan-
dle nor a simple scalar variable containing a filehandle
name, typeglob, or typeglob reference, it is interpreted
as a filename pattern to be globbed, and either a list of
filenames or the next filename in the list is returned,
depending on context. This distinction is determined on
syntactic grounds alone. That means "<$x>" is always a
readline() from an indirect handle, but "<$hash{key}>" is
always a glob(). That's because $x is a simple scalar
variable, but $hash{key} is not--it's a hash element.

You could just use readline():


{
my $fh;
sub from_handle
{
return $fh if defined $fh and fileno $fh;
open ($fh, '<', $0)
or die "Could not open file $0 : $!";
return $fh;
}

sub close_handle
{
close $fh if (defined $fh and fileno $fh);
}
}


while (defined( $_ = readline from_handle ))
{
print $_;
}
 
J

Joe Smith

PerlUser said:
What I would like is to avoid the assignment of $FID and put the
function call directly into the while loop using the <> operator.
Basically:
while (<tst()>) { printf("REC=$_");}

No, you don't want to do that. You should use two statements.
The first one, which opens the input, SHOULD test for errors
and output some sort of warning if the open fails. The second is
while(<$filehandle>)
as you know.

-Joe
 
A

Anno Siegel

PerlUser said:
Hello,
Please give me an idea of how the following scenario can work. I am
use to C reference / dereference concepts, but after reading perlref
half a dozen times and looking at dozens of newsgroups, I have not been
able to come up with a solution. Given the following code and a file
called "out" with a few lines of junk;

Ugh. Why call an input file "out"?
====================
sub tst {
open($FID, "<out");
printf("FID in sub = $FID\n");
return($FID);
}

# Works
$FID = tst();
while (<$FID>) { printf("REC=$_");}
close($FID);

# Works
$FID = *{&tst()}{GLOB};
while (<$FID>) { printf("REC=$_");}
close($FID);

# Works
sysread(tst(), $REC, 100);
printf("REC=${REC}\n");
close($FID);
====================
What I would like is to avoid the assignment of $FID and put the
function call directly into the while loop using the <> operator.
Basically:
while (<tst()>) { printf("REC=$_");}

Why would you want to do that? It looks rather absurd.
I know there is a simple solution to this (a few characters on one side
or the other of tst()), but I have yet been able to find the smoking
gun.

No, you don't know that, and here isn't a simple solution like that. If you
read up on the syntax of <>, (something you should have done before posting)
you'll find it doesn't allow much in the way of "a few characters on one
side or the other" without changing its meaning.

Also, your function tst() is entirely unsuitable to be called that way.
It (re-)opens the input file on each call, so the <> operation would
read the first line again and again. To give it a chance of working,
declare the file handle $FID outside it. Inside, check $FID and only
open the file if it hasn't been opened already (see below).
I am avoiding using any other packages (e.g. no "use" commands...
just built-in functionality).

Why that? Just to make it harder?

Here is one way you can do what you want. It uses overloading of glob
de-referencing for a suitable object. Despite its relative brevity, it
is not what I would call a simple solution.

my $obj = bless [];
print while <$obj>;

my $FID;
sub tst {
open($FID, "out") or die "boo" unless $FID;
printf("FID in sub = $FID\n");
return($FID);
}

use overload '*{}' => 'tst';

Anno
 
T

Tad McClellan

PerlUser said:
open($FID, "<out");


You should always, yes *always*, check the return value from open:

open my $FID, '<out' or die "could not open 'out' $!";
 
P

PerlUser

Thank you all for your replies.

I know most of you commented on error checking and other specific
details. I wanted to keep the script as brief as possible (no
clutter), which is why I did not do a bunch of error checking. Trust
me when I say I have a **** load of error checking in my real script.
I see some people dump way too much code in these posts (and others
that supply not nearly enough) so I just wanted to get the main point
made and leave out the details not relating to the question.

As for your comments:
Brian McCauley: My mistake within the example. The filehandle
reference being returned in my original script still has scope because
the filehandle is being stored within the instance of a class. I use
printf out of habit from my old C++ days. Thank for your explanation
about <...>. I had reviewed the section but something just was not
clicking in my head.
-- (e-mail address removed): That section out of perlop is what I was
missing... Thanks for including it in your response. As mentioned
earlier, I had read it but just missed the connection since I figured
it would work since it was a filehandle that was being passed into the
<...> from the return of the function.
-- Anno Siegel: In the south we do things backwards.... "out" as an
input file just seemed to make sense :) I did read up on the <...>
operator, but based on what I read there was nothing to tell me it
should not work. If the variable holding the return of the function
works, why would not the return of the function itself? That was the
main reason why I wanted to get some input from others who have had
more experience. perl just acts different than other languages, and
these nuances take time to understand. BTW... Thanks for the code
example.

The idea behind this is I was calling a sub within a class that would
return a reference to the filehandle stored in the instance of the
class. Basically, I was trying to refrain from creating local
variables if possible.

Everyone, thanks again for your time.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,184
Messages
2,570,973
Members
47,529
Latest member
JaclynShum

Latest Threads

Top