If a file I'm editing has a new line at the end I can skip to the end of file and then move upwards again line by line with the cursor ending up at a defined position (i.e. the first column in that line) each time.
If, however, there's no new line when following the same routine the cursor will end up at a position defined by the arbitrary length of the last line in that file, which for me at least is not what I want as a user in most cases.
Then again, maybe that's just weird muscle memory acquired through long-term exposure to how text editors usually work.
(That sounds a bit Zen, doesn't it?)
In most of the cases where commas separate things either those things are not allowed to be empty or there has to be at least one thing, so there's no problem. But you have to watch out for cases in which you don't have those conditions because then you get the ambiguity.
If the file has any lines at all, then the last line is terminated by a newline, for the same reason as the first and any other line.
If the last line is missing a newline, then it's an improper text file.
An empty file is just no characters at all. If a file contains nothing but a newline character, then it's a one-line file containing an empty line.
If the newline were optional at the end of a file, then those two cases (empty file versus one-line file with optional newline missing) would not be distinguishable.
The text file representation has to have some sort of unambiguous framing which indicates the presence of each line. Unix chose the terminating newline as that framing.
A lot of tools come from the Unix environment. C came from Unix, and the C <stdio.h> text streams follow Unix conventions when operating in text mode, regardless of platform. So that is to say, unless you fopen a file in binary ("b") mode, text mode is in effect, and text mode means newline-terminated lines. The programming model that you see when manipulating text streams in C is that of lines terminated by '\n', and nothing else. This is true even if you are on Windows, where the actual file has "\r\n" termination, and character 26 at the very end.
C ate the world, especially in the area of tooling, and so that representation and its associated concepts have spread. Other languages imitate the model.
A lot of languages have been written in C in the last 30 years, and it's easy for such languages to be influenced by C's conventions. For instance, I think that Python has essentially the same newline-terminated-line view of text files, on any platform.
Language designers want to give programmers a sane model for working with text files that is platform-independent, and the inspiration from that comes from UNIX via C more than anything due to historic circumstances being what they are.
Plus the text file model is very simple. It has no special case for the last line (no file terminator), and uses a single character for the framing, which is a lot simpler to program with than a two character sequence like CR-LF, where either of the two characters can be missing, or they can be in the wrong order: all these cases to handle in every situation where you're scanning across lines.
cat - > some_filename.txt
To finish the file, you have to add a new line - then, at the start of that line, press Ctrl-DSo with tools where you have to insert an EOF manually like that, it's impossible to have a file that ends without a newline.
`cat` stops reading when read(2) returns an empty string (read(2) doing that is what's interpreted as EOF). Ctrl-D doesn't insert anything. Rather it flushes the terminal's output buffer (the one that's filled with user input) into the underlying program's input.
The terminal does line buffering by default to allow the user to modify the line before submitting it (e.g. deleting with backspace or Ctrl-W). That means that it automatically flushes when reaching the end of line (i.e. the newline). If you flush again with Ctrl-D at the start of a line, that means cat's call to read(2) will return an empty string, since you're flushing an empty buffer.
That means that:
> So with tools where you have to insert an EOF manually like that, it's impossible to have a file that ends without a newline.
is false. It's not impossible, just impractical. You can have a file with an incomplete line at the end by starting a line and hitting Ctrl-D twice. Once to submit the incomplete line, and then again to flush the empty buffer, thereby indicating EOF.