Richard Frith-Macdonald wrote: > Nicola Pero wrote: > >> Ok - it looks silly to discuss too much about this anyway (with all the >> pending stuff) but I can't avoid another one on this :-) >> >> >> >>>> I don't understand why you are assuming that +stringWithContentsOfFile >>>> returning nil is an error. The caller will assess that. In the case of >>>> NSSavePanel, for example, it's a perfectly valid condition. >>>> >>>> >>> <pedantic>Technically a nil return here indicates a failure ... an >>> error. I'ts up to the caller to decide how to deal with that, not to >>> decide whether it's a failure or not.</pedantic> >>> >> >> <pedantic>An 'error', for the programmer using the base library, is when >> the base library generates an exception. Anything else is not an >> error. A nil return here indicates that the file doesn't exist, is >> not readable >> or can't be read. This is considered a valid result, otherwise the API >> would have required an exception - with the name and reason of the >> error - >> to be raised.</pedantic> >> > > Sorry ... but the above is simply not the case. Exceptions are not the > only way of denoting > an error condition and the standard mechanism of indicating an error > during object > construction is to return nil. As a general rule, constructors are > supposed to avoid > raising exceptions, and should document cases where they do since > raising an exception > is not the normal behavior for them. > >> But I agree that it's up to the caller to decide how to deal with a nil >> result, which is why the library should not be logging but letting the >> caller decide what to do. :-) >> >> Yes - it's a very simple (but not very powerful) API ... the idea I >> suppose is that if you want richer control, then you have to use a more >> complex API. >> >> +stringWithContentsOfFile: is a simple high-level wrapper around the >> low-level API, which provides you with a simple and straightforward API >> for reading a file if it's there, and ignore it if it's not or can't be >> read. It's perfect for cases like the NSSavePanel, which need precisely >> that. The fact that it returns nil is to be considered a *feature* of >> the >> library, and using it is *not* a programming error. >> > Returning a nil is a failure indicator ... sure you can consider it a > 'feature', but > that's not really the point - the log is a warning - to indicate > something > that is likely to be a programing error. By 'likely' I mean that it's > a programming > error often enought to be worth logging ... if it was 'always' a > programming error > we would either be writing an NSLog() (no choice about it), or raising > an NSException. > An NSLog() would be used where we know it's an error but expect the > program to > be able to continue without intervention anyway, thoough we might also > use it > where we are fairly certain it's a error. > > I've already said that elsewhere, but perhaps restating will help. > It's common practice > to log possible problems both as an aid to development and for > diagnostic purposes later. > Under Unix, NeXTstep (and now MacOS-X) we commonly log things to > stderr. In NeXT/MacOS/GNUstep gui applications, the naive user never > sees these logs ... > so they don't bother the user ... > but they do provide useful information for programmers. The reason for > not > logging *loads* of stuff is for performance, and so that more serious > problems > don't get lost amidst all the very routine stuff. > > So the 'hierarchy' of logging is like this - > > NSDebugLog() ... interesting circumstances, possibly errors, but not > likely to be of > use logging under normal conditions. Needs to be turned on to occur. > NSWarnLog() ... likely to be an error, almost always worth logging. > Needs to be turned off > if it's not to occur. > NSLog() ... probable error, always considered worth logging. can't be > turned off > NSException ... definite error requiring some intervention if the > program is to continue > running. Results in log and abort otherwise. > > Error handling is a different issue, and is handled by two mechanisms > ... return values > from functions and methods (IMO best used to denote errors which > should be dealt > with immediately in the code), and exceptions (best used to pass error > information > back up the stack to where the program can deal with them in a > different manner). > >> >> >> Good explanation - but then why the following code - >> >> tmp = NSZoneMalloc(zone, fileLength); >> if (tmp == 0) >> { >> NSWarnFLog(@"Malloc failed for file (%s) of length %d - %s", >> thePath, fileLength, GSLastErrorStr(errno)); >> CloseHandle(fh); >> return NO; >> } >> >> is this an error that the programmer has done when calling the method ? >> > > No, that's just a mistake :-) > I think a memory allocation failure causes the program to abort > anyway, and > the log there would never get executed. > >> The >> >> explanation of why you are using NSWarnLog is not very convincing. >> You are checking the result of each operation you do, and producing a >> NSWarnLog is any operation fails. But it's not the programmer's fault if >> memory can't be allocated, or if a file was deleted by another process >> just after the method was called (but before the file was opened), or >> its >> permissions changed in the same way, or if the file is too big or if an >> fseek on the file fails (or if the NFS went down just after the method >> started executing). >> > That's just because some of them should actually be NSlog() or > NSException > cases because they are more severe problems ... and I went through > quickly to > *improve* the situation, rather than spending time trying to perfect it. > >> provided >> This stuff is not in the programmer's control, and not the programmers's >> fault, and a different programming style would not necessarily remove >> the >> cause of the errors - so it should not be a NSWarnLog. Why are you >> against it being a NSDebugLog ? >> >> > Because warn logging should be on by default ... and only (possibly) > turned off for > a 'production' system where you don't want end users to see any of > this if they start > poking around places where they are not expected. > > Why do you want to turn *off* useful information? > >> By the way, it seems you want to always have the calling code separately >> check if the the file is there (and that it's not a dir), then check if >> the file is readable by you, and only then read it using >> +stringWithContentsOfFile:. >> >> Well in the NSSavePanel I don't see how that would help or be a better >> programming style ... it would require us to write a lot more code in >> NSSavePanel to do exactly the same things - read the file if it's there >> and can be read as a file, and ignore the matter in all other cases. >> >> It would also be less efficient, since it would check twice that the >> file >> is readable (basically part of the +stringWithContentsOfFile: would need >> to be duplicated in the caller, which *is* bad programming style and >> cause >> of bugs). >> >> > > It lists the files in a directory, then removes certain names from the > list. > If the .hidden file is not in the list, it does not need to try > reading it. > Even if it couldn't reasonably work that way for some reason, I'd > advocate using - > if ([mgr isReadableFileAtPath: hidden] == YES) > // Read hidden file and do whatever it is we do. > > Certainly there is no cause to duplicate any stringWithContentsOfFile: > code though. > > But in any case, I'm not saying you should definitely not use > 'features' of the API > in ways for which they might not have been intended ... just that you > should be > aware of warnings/logs if you do. > >> >> >> There are millions of reasons why a read from a file can fail without >> any >> programming error - no more memory, NFS server down, NFS network >> problems, >> file removed, permissions changed, cdrom/floppy unmounted, filesystem >> error, harddisk failure, floppy failure, cdrom damaged ... any of these >> can happen at any time; and conditions can very well change between the >> moment that the programmer checks that the file is readable and the >> moment >> that he reads it. Not so uncommon. >> >> > > Not *SO* uncommon ... but still all those conditions form a tiny > minority of > cases. The vast majority of cases in practice are where the programmer > has > provided the name of a file which does not exist or is not accessible for > chmod/chown reasons. And of that vast majority, a substantial minority > are cases where the wrong file name has been given ... genuine > programming > errors by many standard. It's therefore helpful to have a log for > these, and it's > a good thing for programmers to try to avoid them. > >> I can see that some people might want a NSDebugLog of what's >> happening to >> help in debugging weird problems. But it has nothing to do with >> programming errors or programming practice or teaching people how to >> improve/fix their code. >> > > As I said ... ten years ago I'd probably have said that conflating the > two operations > of checking for a file and reading a file made sense for > convenience... since then > I've realised that I make more mistakes than I thought, and many > people make more > mistakes than me - So I now think that checking first usually makes > sense, and anything > that raises peoples awareness of this is probably a good thing. > >> >> >> >> >>> and we ought to let the programmer know so they can improve/fix >>> their code. >>> >> >> The NSSavePanel code is correct, is using the documented API, exactly as >> documented, and efficiently and elegantly - I see no reason to change >> it. >> > I'm not going to dispute that ... much :-) > The code could be made more efficient by not reading the .hidden file > if it does not > exist ... I think whether you consider this more or less elegant is a > matter of taste. > PS. I know warn logs are selectable at base library compile time ... I'd have no problem with (I even like the idea) of having a flag to deselect them at runtime. eg. --GNU-Debug=NoWarn to turn off warnings.
Worthwhile? _______________________________________________ Bug-gnustep mailing list [EMAIL PROTECTED] http://mail.gnu.org/mailman/listinfo/bug-gnustep