I'd like someone to expand on the advantages of the following change in 7.7:
o Stdio The functions read_file(), read_bytes(), write_file() and append_file() now always throw errors upon errors, to allow easier use as errno doesn't have to be checked. read_file() and read_bytes() still returns 0 if the file does not exists.
Specificly for read_file() on files you lack permissions for.
> Stdio.read_file("/etc/shadow"); (1) Result: 0
vs
> Stdio.read_file("/etc/shadow"); Failed to open "/etc/shadow": Permission denied /pkg/pike/intel-debian3_1/7.7.13/pike/7.7.13/lib/modules/Stdio.pmod/module.pmod:1820: Stdio->read_file("/etc/shadow",UNDEFINED,UNDEFINED)
As I see it it only makes it harder to properly handle errors. If Pike had a well developed system for handling errors it would be an improvement, but now it's only going to lead to more and buggier code.
Unless someone can come up with a good explanation* for why it should be changed it should be reverted.
* Like for example "I've extended and documented the error classes. It's obvious and clear how to use them now!". That'd be nice.
could you elaborate why it leads to buggier code? the only thing i can think of, is that catching an error is harder than checking on 0 with if.
greetings, martin.
There are several ways. Some non-hypothetical ones below:
* No one notices the change or can't be bothered :
if( !Stdio.read_file("/etc/foo") ) webbapp_report_fatal("Unable to read /etc/foo");
In this case it will go from reporting the error to the web application user to producing a white page, a page with missing content or a 500 error.
* Someone notices but just want to prevent the rest of the framework from failing:
catch { if( !Stdio.read_file("/etc/foo") ) webbapp_report_fatal("Unable to open /etc/foo"); };
Now you won't just get a broken web page, you will also not get anything in the logs that could tell you forgot to start the framework with sufficient permissions.
I could take the first problem as a necessary evil if it lead to improvements, but I can't see any improvement here. You go from easy error management where you can check errno if you want details, to a situation where you have to check the return code and set up a catch, and then decode what kind of error the catch received. And the code gets uglier.
It seems like noone steps forward and tells us what the benefits are. Is the change reversed?
The benefits are there in the CVS message
revision 1.204 date: 2004/09/01 17:17:08; author: mast; state: Exp; lines: +78 -30 Made read_file, read_bytes, write_file and append_file easier to use by letting them throw on all I/O errors (with the exception that read_file and read_bytes still returns zero if the file doesn't exist at all). For instance, it's not necessary to check the return value from write_file and append_file to ensure that the whole string was written. ----------------------------
and I agree with them. I don't think this breaks much code, if any, only makes the flaws in that code more visible, should it occur. I know that I never check errno after performing Pike file I/O.
The code that breaks is code that doesn't expect a thrown error.
A lot of my code uses 'if' to check the result from those operations; I don't see why errno would be very interesting.
OTOH, Pike is robust enough so the error is caught on a higher level anyway, but I don't think I'm alone in having code that uses if to check on those.
---
On a sidenote, I think Pike still really needs an exception handling syntax.
I can live with write_file and append_file throwing. It's already documented to do that and you can not use if (Stdio.write_file(...)) as is anyway.
It's the read_file and read_bytes changes I'm against. They only make things worse.
I agree. It breaks my start() in a Roxen-module badly in a very annoying way if there would be any read-problems of the files.
This change isn't needed and it breaks things. Please change back!
The new behaviour is to throw when there's a permanent error (eg permission denied). There's lots of code that assumes that read_{file,bytes} return zero only when the file doesn't exist. This is now also the implemented behaviour.
The new behaviour is to throw when there's a permanent error (eg permission denied).
Or on some of them at least. File does not exist is pretty permanent. Anyway, it's broken.
There's lots of code that assumes that read_{file,bytes} return zero only when the file doesn't exist.
There is? I can't think of any offhand where it matters if the file is unreadable or if there is insufficient permissions. If there is that code is broken today. With the proposed change good code will break.
On Tue, Jan 09, 2007 at 10:00:03AM +0000, Peter Bortas @ Pike developers forum wrote:
File does not exist is pretty permanent.
no, if the file does not exist, the next line of the code could create it, if it's needed or just go on without it.
if the file does exist and there is no read permission than that is not the same as a file not existing and should be treated differently. fixing it most likely requires user intervention too.
a program that treats non-existing and unreadable files the same is broken. therefore i like this difference of throwing en error on permisson problems because then i can get away with if(read_file()) in simple programs where i don't mind the crash.
I can't think of any offhand where it matters if the file is unreadable or if there is insufficient permissions.
unreadable or insufficient permissions are the same kind of problem, but non-existing is a different kind of problem.
non-existing in most cases is non-critical, whereas unreadable or insufficient permission may be critical.
greetings, martin.
On Tue, Jan 09, 2007 at 10:00:03AM +0000, Peter Bortas @ Pike developers forum wrote:
File does not exist is pretty permanent.
no, if the file does not exist, the next line of the code could create it, if it's needed or just go on without it.
With that definition no error is permanent. The same line could change the permissions. Several applications actually do.
if the file does exist and there is no read permission than that is not the same as a file not existing and should be treated differently. fixing it most likely requires user intervention too.
They are both errors. If you want to fix the error you must treat it differently, but most Pike applications don't fix errors, they just want to report them to the user in a sane way.
a program that treats non-existing and unreadable files the same is broken.
False.
I can't think of any offhand where it matters if the file is unreadable or if there is insufficient permissions.
unreadable or insufficient permissions are the same kind of problem, but non-existing is a different kind of problem.
They are all different kinds of problems. We can group them in arbitrary ways.
non-existing in most cases is non-critical, whereas unreadable or insufficient permission may be critical.
There is no basis for that statement.
Catching up, and I'd like to give my view of this since I'm responsible for it.
There is lots of code that simply assumes that a zero from read_bytes et al means the file doesn't exist. You can tell since the code happily continues with e.g. some kind of default, or that it simply doesn't process the file at all (think files in a queue). This is very broken behavior for other sorts of I/O errors, as people already have mentioned.
I ran across this on code which happily ignored input because of a permission problem. Nothing was reported, and the system just idled when it was supposed to be doing things. It was of course all too time consuming to figure out what the problem actually was.
My aim with the change was to make the functions as useful as possible, considering they are convenience functions. They should only return for errors that the caller typically wants to handle and throw the rest. My experience, and also all the code I've seen that are using these functions, tells that the error one wants to handle is when the file doesn't exist, and nothing else.
So, the intention is that very little code using these functions should need to be changed. It only starts to behave better since exceptional errors (i.e. installation errors or hardware failures) get reported instead of being essentially ignored. I can only see two cases where changes are necessary:
1. Code that checks errno after getting a zero return value. (I can't recall I've ever seen that.)
2. Code that regularly encounters other (i.e. exceptional, imo) I/O errors but has so far lumped them together with the common nonexisting file error. Such code could probably be improved anyway to report these errors in different ways since they are of different severity.
I'm still against changing anything in Pike that invalidates a lot of old code.
If you want to help people to write useful code, first make a nice exception system with syntactic support, then write *new* functions to support that system.
Looks to me like it will break tons of code. I would like to know how it's a net benefit as well.
pike-devel@lists.lysator.liu.se