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…
Or allow multiple return values like Go. EOF gets returned as an explicit error value and the io.Reader interface is standardized and widely used.
EOF is not a character
121–130 of 136 posts
Re: EOF is not a character
#122Earlier quoted context omitted.
Structs are values and you can return them like any value (or use them as parameters). I'm not sure what you mean about compilers.
See, for instance, here: https://gcc.gnu.org/onlinedocs/gcc-9.3.0/gcc/Incompatibiliti... https://gcc.gnu.org/onlinedocs/gcc-9.3.0/gcc/Code-Gen-Option... https://gcc.gnu.org/onlinedocs/gcc-9.3.0/gcc/Warning-Options...
This is mostly not a practically relevant issue. (Nor are pre-K&R compilers relevant, although something like this could arise among modern compilers.) As far as oddball situations go, it's far from the thorniest to deal with - it doesn't even involve C++.
Re: EOF is not a character
#123Earlier quoted context omitted.
What they mean to say is: when I was working with a language that enforced pure functions, I had to actually consider purity. It's rare to see a way to enforce purity in procedural languages, whereas most fp langs support it.
Are we talking about even roughly the same concept of functional purity [1]? Nothing is stopping a pure function from representing EOF as -1. Implementing IO in a "pure" way, is however another discussion. [1]: https://en.wikipedia.org/wiki/Pure_function
Re: EOF is not a character
#124Another weird thing is that sometimes you can read an EOF, then keep reading more real bytes. So EOF doesn't necessarily mean the permanent end.
https://sourceware.org/bugzilla/show_bug.cgi?id=1190
https://sourceware.org/legacy-ml/libc-alpha/2018-08/msg00003...
> All stdio functions now treat end-of-file as a sticky condition. If you read from a file until EOF, and then the file is enlarged by another process, you must call clearerr or another function with the same effect (e.g. fseek, rewind) before you can read the additional data. This corrects a longstanding C99 conformance bug. It is most likely to affect programs that use stdio to read interactive input from a terminal.
Re: EOF is not a character
#125Earlier quoted context omitted.
No, encoding additional information in unused bits of an int that you return is stupid over-engineering that needs multiple textbooks to grok. Option , on the other hand, is the simplest possible solution for this problem.
I would also like to not that encoding the the Option using the unused bits of the return value is a perfectly valid implementation. But that is exactly what it is, an implementation detail. It could work exactly the same way as today but the programmer wouldn’t have to care about how it was implemented, just whether they got a char or None.
https://play.rust-lang.org/?version=stable&mode=debug&editio...
Re: EOF is not a character
#126Earlier quoted context omitted.
I’m a community college drop out and have never taken a CS class and I use options in my code all the time. It’s just a wrapper around some value that is either Some(value) or None and you need to unwrap it and handle both possibilities for your code to compile. You don’t need to know anything about monads or ADT’s to understand it.
But do you understand that some values of a 32 bit int can be used to encode meta-data about a 8 bit char? If you understand both, which one is conceptually easier to you?
1) It applies exactly the same way to any type, not just char.
2) You don't need to read the man page for every single function that returns an int on the off chance that said int actually contains a bool, a char, or a short plus additional flags.
Re: EOF is not a character
#127Earlier quoted context omitted.
The amusing thing about it is that C does not guarantee that EOF is out-of-band! ISO C says that char must be at least 8 bits, and that int must be at least 16. It is entirely legal to have an implementation that has 16-bit signed char and sizeof(int)==1. In which case -1 is a valid char, and there's no way to distinguish between reading it and getting EOF from getchar().
... which is why no system ever implements things this way. There are many portions of the C spec that can be ignored. Large swaths of the C standard were built during the heyday of computer design, when you had all sorts of wacky sizes, behaviors and abstractions. Lots of "undefined behavior" is effectively deterministic, because all modern computers have converged to do so many things the same way.
Re: EOF is not a character
#128Earlier quoted context omitted.
No, encoding additional information in unused bits of an int that you return is stupid over-engineering that needs multiple textbooks to grok. Option , on the other hand, is the simplest possible solution for this problem.
I would also like to not that encoding the the Option using the unused bits of the return value is a perfectly valid implementation. But that is exactly what it is, an implementation detail. It could work exactly the same way as today but the programmer wouldn’t have to care about how it was implemented, just whether they got a char or None.
Re: EOF is not a character
#129In the beginning, there was the int. In K&R C, before function prototypes, all functions returned "int". ("float" and "double" were kludged in, without checking, at some point.) So the character I/O functions returned a 16-bit signed int. There was no way to return a byte, or a "char". That allowed room for out of band signals such as EOF. It's an artifact of that era. Along with "BREAK", which isn't a character eith…
GCC only outputs a warning by default: "warning: return type defaults to ‘int’ [-Wimplicit-int]"
Re: EOF is not a character
#130Another weird thing is that sometimes you can read an EOF, then keep reading more real bytes. So EOF doesn't necessarily mean the permanent end.
The EOF condition for stdio functions is supposed to be sticky, although glibc didn't implement it correctly until 2.28: https://sourceware.org/bugzilla/show_bug.cgi?id=1190 https://sourceware.org/legacy-ml/libc-alpha/2018-08/msg00003... > All stdio functions now treat end-of-file as a sticky condition. If you read from a file until EOF, and then the file is enlarged by another process, you must call clearerr or anot…
Although interestingly somehow I'm still seeing the old behavior in Debian Buster with glibc 2.28 with python3.
import sys
while True:
b = sys.stdin.read(1)
print(repr(b))
With old glibc with both python2 and python3 the EOF isn't sticky (as expected). With 2.28 with python2 the EOF is sticky (like you said). With 2.28 with python3 it's not sticky for some reason.