In IO::Handle§

See primary documentation in context for method eof

method eof(IO::Handle:D: --> Bool:D)

Non-blocking. Returns True if the read operations have exhausted the contents of the handle. For seekable handles, this means current position is at or beyond the end of file and seeking an exhausted handle back into the file's contents will result in eof returning False again.

On non-seekable handles and handles opened to zero-size files (including special files in /proc/), EOF won't be set until a read operation fails to read any bytes. For example, in this code, the first read consumes all of the data, but it's only until the second read that reads nothing would the EOF on a TTY handle be set:

$ echo "x" | raku -e 'with $*IN { .read: 10000; .eof.say; .read: 10; .eof.say }'
False
True

In IO::CatHandle§

See primary documentation in context for method eof

method eof(IO::CatHandle:D: --> Bool:D)

Returns True if the read operations have exhausted the source handle queue, including the contents of the last handle. Note: calling this method may cause one or more .on-switch calls, while the source handle queue is examined, and the source handle queue may get exhausted.

(my $f1 = 'foo'.IO).spurt: 'foo';
(my $f2 = 'bar'.IO).spurt: 'bar';
with IO::CatHandle.new: :on-switch{ print 'SWITCH! ' }$f1$f2 {
                   # OUTPUT: «SWITCH! » 
    .eof.say;      # OUTPUT: «False␤» 
    .readchars(3);
    .eof.say;      # OUTPUT: «SWITCH! False␤» 
 
    .slurp;        # OUTPUT: «SWITCH! » 
    .eof.say;      # OUTPUT: «True␤» 
}

The same caveats for non-seekable handles and empty files that apply to IO::Handle.eof apply here.