reddit discussion on replacing Python in 0install

Steven Schveighoffer schveiguy at yahoo.com
Tue Jun 11 08:57:38 PDT 2013


On Tue, 11 Jun 2013 01:37:52 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail at 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


More information about the Digitalmars-d mailing list