Live data from Hacker News

EOF is not a character

ruslanspivak.com

61–70 of 136 posts

Re: EOF is not a character

#61
post #19

Like NULL, confusion over EOF is a problem which can be eliminated via algebraic types. What if instead of a char, getchar() returned an Option ? Then you can pattern match, something like this Rust/C mashup: match getchar() { Some(c) => putchar(c), None => break, } Magical sentinels crammed into return values — like EOF returned by getchar() or -1 returned by ftell() or NULL returned by malloc() — are one of C's dra…

”What if instead of a char, getchar() returned an Option?”

Getchar doesn’t return a char; it returns an int (https://en.cppreference.com/w/c/io/getchar).

⇒ if C didn’t do automatic conversions from int to char, we would have that (in a minimalistic sense)

That wouldn’t work for ftell and malloc (and, in general, most of the calls that set errno), though.

Re: EOF is not a character

#62
post #19

Like NULL, confusion over EOF is a problem which can be eliminated via algebraic types. What if instead of a char, getchar() returned an Option ? Then you can pattern match, something like this Rust/C mashup: match getchar() { Some(c) => putchar(c), None => break, } Magical sentinels crammed into return values — like EOF returned by getchar() or -1 returned by ftell() or NULL returned by malloc() — are one of C's dra…

Option, given that in C ‘characters’ means bytes, not code points.

Re: EOF is not a character

#63

Earlier quoted context omitted.

Wikipedia supports this: > Character 26 was used to mark "End of file" even if the ASCII calls it Substitute, and has other characters for this. Number 28 which is called "File Separator" has also been used for similar purposes. [1] I think today we would think of character 4 (End of Transmission, Ctrl-D) as the end of file/input marker, but historically Character 26/Ctrl-Z was used, even on disk. 1: https://en.wikip…

See, this is why you should not believe Wikipedia. The DOS syscall interface has no concept of an EOF character. ^Z being considered EOF was a feature of the COPY command, later replicated by the runtimes of various languages targetting DOS. http://jdebp.info/FGA/dos-character-26-is-not-special.html

I think TYPE would also treat ^Z as a terminator of the file. I think it was common in DOS to have binary files with a textual header followed by ^Z, that would hide the binary part.

Re: EOF is not a character

#64
post #19

Like NULL, confusion over EOF is a problem which can be eliminated via algebraic types. What if instead of a char, getchar() returned an Option ? Then you can pattern match, something like this Rust/C mashup: match getchar() { Some(c) => putchar(c), None => break, } Magical sentinels crammed into return values — like EOF returned by getchar() or -1 returned by ftell() or NULL returned by malloc() — are one of C's dra…

> Magical sentinels crammed into return values — like EOF returned by getchar() or -1 returned by ftell() or NULL returned by malloc() — are one of C's drawbacks.

They're part of the C standard library. The POSIX I/O APIs don't have these problems. The Linux I/O system calls are even better because they don't have errno.

Honestly, the C standard library just isn't that good. Freestanding C is a better language precisely because it omits the library and allows the programmer to come up with something better.

Re: EOF is not a character

#65
post #19

Like NULL, confusion over EOF is a problem which can be eliminated via algebraic types. What if instead of a char, getchar() returned an Option ? Then you can pattern match, something like this Rust/C mashup: match getchar() { Some(c) => putchar(c), None => break, } Magical sentinels crammed into return values — like EOF returned by getchar() or -1 returned by ftell() or NULL returned by malloc() — are one of C's dra…

Option , given that in C ‘characters’ means bytes, not code points.

A byte could be 6,7,8, or 9 bits depending on platform.

Re: EOF is not a character

#66

Earlier quoted context omitted.

It's not a great snark given that the C standard considers the signedness of char to be implementation defined, making -1 a valid option, sometimes.

I'm sorry you don't find it great (I still do). Integers are not characters. Integers are numbers like -1337, 0, and 42. Characters are things that compose strings of text. These are not the same kind of thing at all. Just because APIs may be leaky, and some of these APIs are held in very high regard doesn't change that fact.

In the end, integers, floating point numbers, "text\n", emojis etc. are just sequences of bytes. You choose to acknowledge it and take advantage of it, or you don't.

Re: EOF is not a character

#67

So what is CP/M-style character 26? Isn’t that documented as end-of-file?

Perhaps a marginally better title would be "EOF is not a character [on Unix]". There are some OS that have an explicit EOF character, but it seems to have been the less common approach historically. CP/M featured an explicit end of file marker because the file system didn't bother to handle the problem of files which were not block-aligned, so the application layer needed to detect where the actual end of the file wa…

This also afflicts the xmodem protocol.

Re: EOF is not a character

#68

I find it interesting that Rust's `Read` API for `read_to_end` [1] states that it "Read[s] all bytes until EOF in this source, placing them into buf", and stops on conditions of either `Ok(0)` or various kinds of `ErrorKind`s, including `UnexpectedEof`, which should probably never be the case. [1]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read...

The reason for that is that, for simplicity's sake, all of the I/O functions share the same error type. `UnexpectedEof` should never be returned from `read_to_end`, but it can be returned from `read_exact`.

Re: EOF is not a character

#69

Earlier quoted context omitted.

Option , given that in C ‘characters’ means bytes, not code points.

A byte could be 6,7,8, or 9 bits depending on platform.

Yes, but Rust doesn’t support those. So on platforms where both C and Rust run, bytes will be 8 bits.

Either way, no platform defines bytes to be Unicode code points.

Re: EOF is not a character

#70
This is very well explained in the classic book The UNIX Programming Environment, by Kernighan and Pike, in page 44:

Programs retrieve the data in a file by a system call ... called read. Each time read is called, it returns the next part of a file ... read also says how many bytes of the file were returned, so end of file is assumed when a read says "zero bytes are being returned" ... Actually, it makes sense not to represent end of file by a special byte value, because, as we said earlier, the meaning of the bytes depends on the interpretation of the file. But all files must end, and since all files must be accessed through read, returning zero is an interpretation-independent way to represent the end of a file without introducing a new special character.

Read what follows in the book if you want to understand Ctrl-D down cold.

Post reply on HN