How can I autoflush a Perl 6 filehande?
Asked Answered
C

4

6

There are a couple of answers for Perl 6 back in its Parrot days and they don't seem to work currently:

This is Rakudo version 2017.04.3 built on MoarVM version 2017.04-53-g66c6dda implementing Perl 6.c.

The answer to Does perl6 enable “autoflush” by default? says it's enabled by default (but that was 2011).

Here's a program I was playing with:

$*ERR.say: "1. This is an error";
$*OUT.say: "2. This is standard out";

And its output, which is an unfortunate order:

2. This is standard out
1. This is an error

So maybe I need to turn it on. There's How could I disable autoflush? which mentions an autoflush method:

$*ERR.autoflush = True;
$*ERR.say: "1. This is an error";
$*OUT.say: "2. This is standard out";

But that doesn't work:

No such method 'autoflush' for invocant of type 'IO::Handle'

I guess I could fake this myself by making my IO class that flushes after every output. For what it's worth, it's the lack of this feature that prevented me from using Perl 6 for a particular task today.

As a secondary question, why doesn't Perl 6 have this now, especially when it looks like it used to have it? How would you persaude a Perl 5 person this isn't an issue?

Comate answered 8/7, 2017 at 15:4 Comment(0)
K
4

This might not have worked yet when you asked the question, but:

$*ERR.out-buffer = False;
$*ERR.say: "1. This is an error";
$*OUT.say: "2. This is standard out";

It's a bit hard to find, but it's documented here.

Works for me in Rakudo Star 2017.10.

Kursk answered 16/12, 2017 at 13:5 Comment(3)
FWIW TTY handles aren't buffered and setting this isn't needed. OP's observed behaviour is due to 2017.04 still using libuv's async IO for output.Anesthetic
Setting $*ERR.out-buffer and $*OUT.out-buffer to False is still useful when your output is redirected or piped (e.g. 2>&1 | less).Kursk
This is not nearly the same as autoflush ... unbuffered streams effectively flush after every byte, whereas autoflush flushes after each write or print, which is generally a lot faster.Ferrigno
B
6

There was an output refactory very recently. With my local version of rakudo i can't get it to give the wrong order any more (2017.06-173-ga209082 built on MoarVM version 2017.06-48-g4bc916e)

There's now a :buffer argument to io handles that you can set to a number (or pass it as :!buffer) that will control this.

I assume the default if the output isatty is to not buffer.

Birthday answered 8/7, 2017 at 16:59 Comment(0)
K
4

This might not have worked yet when you asked the question, but:

$*ERR.out-buffer = False;
$*ERR.say: "1. This is an error";
$*OUT.say: "2. This is standard out";

It's a bit hard to find, but it's documented here.

Works for me in Rakudo Star 2017.10.

Kursk answered 16/12, 2017 at 13:5 Comment(3)
FWIW TTY handles aren't buffered and setting this isn't needed. OP's observed behaviour is due to 2017.04 still using libuv's async IO for output.Anesthetic
Setting $*ERR.out-buffer and $*OUT.out-buffer to False is still useful when your output is redirected or piped (e.g. 2>&1 | less).Kursk
This is not nearly the same as autoflush ... unbuffered streams effectively flush after every byte, whereas autoflush flushes after each write or print, which is generally a lot faster.Ferrigno
C
3

Rakudo doesn't support autoflush (yet). There's a note in 5to6-perlvar under the $OUTPUT_AUTOFLUSH entry.

raiph posted a comment elsewhere with a #perl6 IRC log search showing that people keep recommending autoflush and some other people keep saying it's not implemented. Since it's not a documented method (although flush is), I suppose we'll have to live without for a bit.

Comate answered 8/7, 2017 at 15:19 Comment(2)
This is the simple, unsatisfactory answer but I've added a secondary question asking why we don't have it. If you have the rationale or technical limitation details, I think that would be useful to people.Comate
The doc was misworded (now amended). It's not that autoflush isn't implemented, it's buffering that's not implemented (and by extension the autoflush). I suspect the behaviour you're seeing is because we used to use async IO in the backend even for sync IO on frontend. That part has now (since 2017.06) been made sync. Also, there's current experimental work to add buffering, possibly with the :buffer argument to open (currently off by default, may be enabled by default at a later date).Anesthetic
S
1

If you're primarily interested in STDOUT and STDERR, the following seems to reopen them without buffering (auto-flushed):

$*OUT = $*OUT.open(:!buffer);
$*ERR = $*ERR.open(:!buffer);

This isn't thoroughly tested yet, and I'm surprised this works. It's a funny API that lets you re-open an open stream.

Sym answered 20/9, 2017 at 8:17 Comment(1)
No buffering is not the same as autoflush.Ferrigno

© 2022 - 2024 — McMap. All rights reserved.