On Tue, 11 Jun 2013 01:37:52 -0400, Andrei Alexandrescu <seewebsiteforem...@erdani.org> wrote:

On 6/11/13 12:04 AM, David Nadlinger wrote:
On Tuesday, 11 June 2013 at 04:02:59 UTC, Andrei Alexandrescu wrote:
The test program is flawed; writeln() writes to stdout, and the
redirection is to stdin.

Wouldn't stdin be fd 0?

David

Oh indeed my bad. But the test is still flawed. Consider:

import std.stdio;
int main()
{
     return printf("test\n") < 0;
}

This should return 1 if printf fails. It succeeds for 1</dev/null.

This actually gave me an idea of why it doesn't fail.

This code DOES fail:

import std.stdio;

int main()
{
    writeln("hello");
    std.stdio.stdout.flush();
    return 0;
}

Here is the (interesting) issue:

FILE *, and likewise std.stdio.File, which uses FILE * as it's implementation, is a buffered stream.

An interesting problem to solve for buffered streams is when to flush the buffer. The most efficient thing to do is to wait until the entire buffer is full, then flush it (call the syscall to write the data to the handle/descriptor). However, in an INTERACTIVE console, you want to flush more frequently, in case the data is coming out sporadically.

HOWEVER, the C runtime first checks to see if the file descriptor is a console. If it is, it sets the flag indicating that it should flush on newlines, otherwise, it does not. Instead of seeing 4K (or whatever buffer size is) of data at a time, the user sees 1 line at a time, much more parseable by a human. This is why cat'ing a file to another file is much more efficient than cat'ing it to the console.

Important to note is that /dev/null is NOT a console :)

So what is happening is, writeln("hello") is writing "hello\n" to the FILE *, which sits in the buffer, no flushing occurs, because /dev/null is not a console. However, upon calling flush, it fails, because the file descriptor is invalid.

Upon exit, std.stdio.stdout relies on core.stdc.stdio.stdout to flush the data (in fact, I don't even think stdout's dtor is called). And C's stdout does not throw an exception or alter the exit code. This is why you have no visible errors.

If D did NOT rely on C's FILE *, it may have a chance to throw an exception on program exit (but likely wouldn't because the buffer is likely GC based and therefore can't be accessed on the dtor :)

Re: different shells behaving differently, depending on how the individual shells are implemented can affect how this plays out.

-Steve

Reply via email to