9
\$\begingroup\$

Write a program or function with the following functionality:

  • The program/function first attempts to write the string Hello, world! to the standard output stream. (No other forms of output are acceptable for this challenge, as the focus is very much on the I/O rather than the trivial behaviour of the program itself.) Depending on whether it succeeded:
    • If it succeeded in outputting Hello, world!, the program/function exits without any further behaviour.
    • If it failed to produce the correct output due to an error, the program/function attempts to write the string Error writing "Hello, world!" to the standard error stream. (For the purposes of this challenge, you don't need error handling for the error handling itself.)

Clarifications

  • Your program/function will be run with no input (unless it's written in a language which absolutely requires input to work, in which case it will be run with the simplest possible input).

  • When producing output, you may also produce a single trailing newline if you wish, but doing so is not mandatory.

  • The definition of "error writing to standard output" that your program implements must treat at least the following cases as errors:

    • Standard output being nonexistent (i.e. stdout is a closed filehandle, no file descriptor 1 exists, or however those cases translate to the language and OS you're using);
    • Standard output referring to a file on a disk that has no free space left;
    • Standard output connecting to another program, which has already closed its end of the connection.

    and must treat at least the following cases as success (i.e. not an error):

    • Standard output connects to a terminal, and Hello, world! is displayed onscreen.
    • Standard output connects to a file, and Hello, world! is written into the file.

    You can choose the details of what counts as an output error, so long as it's consistent with the above rules.

  • Your program/function should not crash upon encountering any of the error situations listed above. It's up to you what exit code you use.

  • Your program/function should not describe the nature of the encountered error on the standard error stream; it should just print the string specified above. Extraneous output on standard error (e.g. compiler warnings) is only legal if it's produced unconditionally, regardless of whether an error is encountered or not.

  • Your program only needs to work on one operating system (although it must be one on which the errors listed above make sense; I've tried to keep them general enough to work on most multitasking consumer operating systems, but weirder operating systems may well be excluded from this challenge). If your program is nonportable, list the assumptions it needs to run in the title of your submission.

  • This task may not be possible in every language (not every language allows a program to handle output errors in a custom way). You'll have to pick a language where it is possible.

  • Make sure that your program/function works! Don't just trust the documentation of library functions to do what they say they do. The error handling of simple output functions often turns out to be broken in practice, even if the functions claim to handle errors in theory.

Test cases

Here's a way to simulate each of the error conditions above using bash on Linux (you don't have to use Linux, but it's likely the easiest system to test this on):

your_program_here >&-           # nonexistent stdout
your_program_here > /dev/full   # out of disk space
mkfifo test  # note: change "test" to a filename that isn't in use
true < test &
your_program_here > test        # connecting to a program that doesn't want input
rm test      # clean up the FIFO we used earlier

The first two testcases are deterministic. The last isn't (it relies on a race condition); for testing purposes, I recommend adding a delay between the start of your program and the actual output to standard output, in order to ensure that the race condition is resolved in the way that exposes the error.

Victory condition

This is a challenge, so shorter is better. As (nearly) always, we're measuring the length of the program in bytes.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Do you know if there is a way to test this on Windows? I can test the first criterion, but not the part about the disk being full... \$\endgroup\$ Apr 12, 2017 at 6:04
  • \$\begingroup\$ To reduce the race condition, could you use sleep 1 < test; (sleep 2; your_program_here) > test? \$\endgroup\$
    – Neil
    Apr 12, 2017 at 7:43
  • \$\begingroup\$ Related \$\endgroup\$
    – JayCe
    Sep 6, 2018 at 17:12

10 Answers 10

6
\$\begingroup\$

Bash, 71 60 bytes

h=Hello,\ world!
(echo $h)2>&-||echo Error writing \"$h\">&2

Try it online!

How it works

After saving Hello, world! to the variable h, we do the following.

First, (echo $h)2>&- attempts to print Hello, world! to STDOUT. 2>&- is required to prevent displaying the error message echo: write error: Bad file descriptor in case the write fails. Since writing to a named pipe that doesn't accept input would kill the Bash program with signal 13 (SIGPIPE), we execute the command in a subshell ((...)), so only the subshell will get killed.

Finally, if printing to STDOUT failed, the subshell will exit with a non-zero status code (141 for SIGPIPE, 1 for a generic error), so echo Error writing \"$h\">&2 prints the desired message to STDERR.

\$\endgroup\$
0
2
\$\begingroup\$

Python 2, 65 bytes

h='Hello, world!'
try:print h
except:exit('Error writing "%s"'%h)

Two bytes could be saved by printing single quotes.

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Zsh, 55 bytes

h=Hello,\ world!
2>&-<<<$h||<<<'Error writing "'$h\">&2

Unlike its cousin Bash, Zsh refuses to die because of a broken pipe.

Try it online!

\$\endgroup\$
1
\$\begingroup\$

C (gcc), 87 86 bytes

f(){signal(13,1);write(1-puts("Hello, world!"),"Error writing \"Hello, world!\"",29);}

Try it online!

Ungolfed

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void f(void)
{
    signal(SIGPIPE, SIG_IGN); // Works (and is required) on TIO. YMMV
    int fd = (puts("Hello, world!")) < 0 ? 2 : -13;
    write(fd, "Error writing \"Hello, world!\"", 29);
}
\$\endgroup\$
5
  • \$\begingroup\$ how do you know what return puts? here says just it is >=0 for to be all ok... \$\endgroup\$
    – user58988
    Apr 12, 2017 at 18:51
  • \$\begingroup\$ puts returns the number of bytes that have been written or -1 in case of an error, so it either returns 14 (Hello World plus newline) or -1. (That may be platform-specific, but this is how it behaves with glibc.) \$\endgroup\$
    – Dennis
    Apr 12, 2017 at 18:53
  • \$\begingroup\$ K&R2 says it return EOF [-1 praticly] if error; or a value not negative if all ok \$\endgroup\$
    – user58988
    Apr 12, 2017 at 19:08
  • 1
    \$\begingroup\$ On PPCG, languages are defined by their implementation, and gcc/glibc behave like I said they do. \$\endgroup\$
    – Dennis
    Apr 12, 2017 at 19:15
  • \$\begingroup\$ i prefer the old book \$\endgroup\$
    – user58988
    Apr 12, 2017 at 19:16
1
\$\begingroup\$

PowerShell, 80 Bytes

try{echo($h="Hello, World!") -ea 4}catch{$host.ui|% *rL* "Error writing ""$h"""}

explained:

try{
    #Attempt to 'echo' (write output) the string, and assign it to $h
    #Make sure the 'error action' is set to '4' to make it a terminating error.
    echo($h="Hello, World!") -ea 4
} catch { 
    #Use the "WriteErrorLine" function in $host.ui to stderr
    $host.ui|% *rL* "Error writing ""$h"""
}

haven't managed to actually try this when it errors, but it definitely ~should~ work.

\$\endgroup\$
4
  • \$\begingroup\$ The error message should be written to STDERR. Writing it to STDOUT isn't possible if an error occurs during the first write attempt. \$\endgroup\$
    – Dennis
    Apr 12, 2017 at 16:27
  • \$\begingroup\$ @Dennis thanks for that, updated there, didn't read the question fully. \$\endgroup\$
    – colsw
    Apr 12, 2017 at 21:37
  • \$\begingroup\$ Afaict PowerShell only catches fatal exceptions, so you'd need Write-Host -ErrorAction Stop or something like that. Also, the throw produces additional debugging ingormation apart of the line it should print, which by the way should have a lowercase W and double quotes around the HW string. \$\endgroup\$
    – Dennis
    Apr 12, 2017 at 22:19
  • \$\begingroup\$ @Dennis the additional debug info has crushed me, answer updated there now. \$\endgroup\$
    – colsw
    Apr 13, 2017 at 15:44
0
\$\begingroup\$

Perl 5, 51 bytes

requires -M5.01, which is free

say$h="Hello, world!"or die"Error writing \"$h\"$/"

Tested in Strawberry Perl 5.24.0 by running the program as-is (printed to standard output) and by running

print f $h="Hello, world!"or die"Error writing \"$h\"$/"

(printed to standard error). I don't know how to test for other errors using Strawberry, but they should be handled the same….

\$\endgroup\$
6
  • \$\begingroup\$ As far as I can tell, this doesn't work. tio.run/nexus/bash#jY3NDoIwEITvfYq1IXCiiD83ys3Ei2/… (The string is also missing a comma.) \$\endgroup\$
    – Dennis
    Apr 12, 2017 at 6:24
  • \$\begingroup\$ I don't know what to make of that page you linked to; can you explain, please? Also, note that the script needs to work on one OS only. And I'll add the comma; thanks. \$\endgroup\$
    – msh210
    Apr 12, 2017 at 6:27
  • \$\begingroup\$ Output should display Hello, world! after === 1 === and nothing after the others. Debug should display nothing after === 1 === and Error writing "Hello, world!" after the others. I'm aware that your program doesn't have to work on TIO, but print f... shows the intended error messages while the original program does not. \$\endgroup\$
    – Dennis
    Apr 12, 2017 at 6:31
  • \$\begingroup\$ "Output" and "Debug" both display nothing as far as I see. I also don't know what the "Header" and "Footer" sections are supposed to be. And I'm wholly unfamiliar with TIO, but note that Strawberry Perl runs on MS Windows. \$\endgroup\$
    – msh210
    Apr 12, 2017 at 6:37
  • \$\begingroup\$ Hat-tip to Dennis for the idea of storing the string in a variable (though I probably would've thought of it had I not seen it there). \$\endgroup\$
    – msh210
    Apr 12, 2017 at 6:38
0
\$\begingroup\$

REXX, 111 106 bytes

signal on notready
a='Hello, world!'
_=lineout(,a)
exit
notready:_=lineout('stderr','Error writing "'a'"')

The program relies on there being a stream called 'stderr'. This will probably not be the case on IBM systems.

\$\endgroup\$
0
\$\begingroup\$

C, 77 bytes

f(a){a="Error writing \"Hello, world!\"";write(1,a+15,13)-13&&write(2,a,29);}

for call

main(){f(1); return 0;}
\$\endgroup\$
1
  • \$\begingroup\$ On which platform did you test this? It doesn't work on Linux if a broken pipe is encountered. \$\endgroup\$
    – Dennis
    Apr 12, 2017 at 19:31
0
\$\begingroup\$

Javascript, 79 76 bytes

try{(l=console).log(a="Hello, world!")}catch(e){l.error('Error writing '+a)}
\$\endgroup\$
3
  • \$\begingroup\$ Note that the string you should output is 'Hello, world!', which is one byte longer than what you use. Also, I suppose assigning a inside the call to console.log would be shorter (1B) and removing the semicolon after l.log(a) saves another byte. \$\endgroup\$
    – Luke
    Apr 12, 2017 at 15:05
  • \$\begingroup\$ @Luke Thanks, That was quite a big mistake! \$\endgroup\$ Apr 12, 2017 at 15:08
  • 1
    \$\begingroup\$ try{(l=console).log(a="Hello, world!")}catch(e){l.error('Error writing '+a)} for 76 bytes. First, console is assigned to l, then "Hello, world!' is assigned to a, and then it's executed. \$\endgroup\$
    – Luke
    Apr 12, 2017 at 15:10
0
\$\begingroup\$

R, 91 bytes

s="Hello, world!"
tryCatch(cat(s),error=function(e)cat('Error writing "','"',file=2,sep=s))

Try it online!

I tried erroring it by running it with cat(s,file=12) instead of cat(s), and it prints the correct text to stderr. This is an invalid connection error otherwise.

\$\endgroup\$
1
  • \$\begingroup\$ Any idea how to test for other output errors? \$\endgroup\$
    – JayCe
    Jul 13, 2018 at 19:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.