Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
653 views
in Technique[技术] by (71.8m points)

perl - is it allowed to pass pipes to constructors?

I tried to do something very fancy in Perl, and I think I'm suffering the consequences. I don't know if what I was trying to do is possible, actually.

My main program creates a pipe like this:

pipe(my $pipe_reader, my $pipe_writer);

(originally it was pipe(PIPE_READER, PIPE_WRITER) but I changed to regular variables when I was trying to debug this)

Then it forks, but I think that is probably irrelevant here. The child does this:

my $response = Response->new($pipe_writer);

The constructor of Response is bare bones:

sub new {
    my $class = shift;
    my $writer = shift;

    my $self = {
        writer => $writer
    };
    bless($self, $class);
    return($self);
 }

Then later the child will write its response:

$response->respond(123, "Here is my response");

The code for respond is as follows:

sub respond {
    my $self = shift;
    my $number = shift;
    my $text = shift;
    print $self->{writer} "$number
";
    print $self->{writer} "$text
";
    close $self->{writer}
}

This triggers a strange compile error: 'String found where operator expected ... Missing operator before "$number "?' at the point of the first print. Of course this is the normal syntax for a print, except that I have the object property instead of a normal handle AND it happens to be a pipe, not a file handle. So now I'm wondering if I'm not allowed to do this.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

From print

If you're storing handles in an array or hash, or in general whenever you're using any expression more complex than a bareword handle or a plain, unsubscripted scalar variable to retrieve it, you will have to use a block returning the filehandle value instead, ...

print { $files[$i] } "stuff
";
print { $OK ? *STDOUT : *STDERR } "stuff
";

(my emphasis)

So you need

print { $self->{writer} } "$number
";

Or, per Borodin's comment

$self->{writer}->print("$number
");

The syntax of print is special, see for example this post and this post. For one, after print must come either a "simple" filehandle or a block evaluating to one, as quoted above, to satisfy the parser.

But with the dereference (arrow) operator the filehandle is found to be an IO::File object? and so its parent's IO::Handle::print method is invoked on it. Prior to v5.14 there had to be use IO::Handle; for this to work, though not anymore. See this post and links in it for more.

Note that print FILEHANDLE LIST is not an indirect method call, even as it may appear to be. It is just a function call to the print builtin under rather special syntax rules. It is only with an explicit -> that an IO::Handle method gets called.


? It is either blessed into the class as the method call is encountered (and fails), or at creation; I can't find it in docs or otherwise resolve whether filehandles are blessed at creation or on demand

perl -MScalar::Util=blessed -wE'
    pipe(RD,WR);                   
    say *WR{IO};                   #--> IO::File=IO(0xe8cb58)
    say blessed(WR)//"undef";      #--> undef
'

(warns of unused RD) ? We can't do this with lexical filehandles as they are not in the symbol table.

But once needed a filehandle is an IO::File or IO::Handle object (depending on Perl version).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...