digitalmars.D - Eof - to return or to throw?
- Dawid =?UTF-8?B?Q2nEmcW8YXJraWV3aWN6?= (39/39) Feb 12 2007 I've just asked Kris why mango is not throwing Eof in it's I/O operation...
- Andrei Alexandrescu (See Website For Email) (16/69) Feb 12 2007 It's very simple, really: from error codes to throwing is a shorter and
- Dawid =?UTF-8?B?Q2nEmcW8YXJraWV3aWN6?= (2/14) Feb 13 2007 That is a nice. I'll have to use that in my code.
- Frits van Bommel (25/77) Feb 12 2007 In fact, the first one better. But only because the lack of typos :P.
- Dawid =?UTF-8?B?Q2nEmcW8YXJraWV3aWN6?= (18/41) Feb 13 2007 As was thinking about multiple reads in the code. Like:
- Dawid =?UTF-8?B?Q2nEmcW8YXJraWV3aWN6?= (16/27) Feb 13 2007 Kristian Kilpi has given me an idea:
- Frank Benoit (keinfarbton) (7/7) Feb 12 2007 Reaching the eof is not an error, it is the expected behaviour.
- Dawid =?UTF-8?B?Q2nEmcW8YXJraWV3aWN6?= (38/43) Feb 13 2007 I personaly have always wondered while people are thinking about excepti...
- Kristian Kilpi (21/64) Feb 13 2007 Reaching EOF is not an error, of course, but reading while at EOF should...
- Dawid =?UTF-8?B?Q2nEmcW8YXJraWV3aWN6?= (17/26) Feb 13 2007 I see that your talking about something more then just error - exception
I've just asked Kris why mango is not throwing Eof in it's I/O operations instead of returning it. After short discusion he told me to ask about your opinons on NG (probably to stop me from distrupting him ;) ). So here am I. Two versions of same functionality. SomeIOClass { /* throws Eof, 0 == nothing available */ return uint readWithThrowingEof(void[] buf); /* -1 == eof, 0 == nothing available */ return int readWithReturningEof(void[] buf); } Which is better? I've always thought about returning Eof as an workaround when you can't throw it or it is too costly. Like in C. I mean: try { auto amount = io.readWithThrowingEof(buf); useData(buf, amount); } catch (Eof e) { /* do smth */ } Isn't any worse than: auto amount = io.readWithReturningEof(buf); if (ammount >= 0) { useData(buf, amount); } else if (ammount == -1) { /* do smth */ } 6 lines vs. 6 lines But when dealing with multiple reads, try block is _much_ better. In ideal situation you can only have one try {} catch {} and just read, use, read, use etc. I can come with many examples where catching/throwing Eof is more flexible both for implementator and library user and the difference is BIG. Especialy in D with great exception support. But are there cases where readWithReturningEof is better? Can someone give me a snippet that we could discuse on? I really have no idea where returning magical value Eof could be more handy than throwing it.
Feb 12 2007
Dawid Ciężarkiewicz wrote:I've just asked Kris why mango is not throwing Eof in it's I/O operations instead of returning it. After short discusion he told me to ask about your opinons on NG (probably to stop me from distrupting him ;) ). So here am I. Two versions of same functionality. SomeIOClass { /* throws Eof, 0 == nothing available */ return uint readWithThrowingEof(void[] buf); /* -1 == eof, 0 == nothing available */ return int readWithReturningEof(void[] buf); } Which is better? I've always thought about returning Eof as an workaround when you can't throw it or it is too costly. Like in C. I mean: try { auto amount = io.readWithThrowingEof(buf); useData(buf, amount); } catch (Eof e) { /* do smth */ } Isn't any worse than: auto amount = io.readWithReturningEof(buf); if (ammount >= 0) { useData(buf, amount); } else if (ammount == -1) { /* do smth */ } 6 lines vs. 6 lines But when dealing with multiple reads, try block is _much_ better. In ideal situation you can only have one try {} catch {} and just read, use, read, use etc. I can come with many examples where catching/throwing Eof is more flexible both for implementator and library user and the difference is BIG. Especialy in D with great exception support. But are there cases where readWithReturningEof is better? Can someone give me a snippet that we could discuse on? I really have no idea where returning magical value Eof could be more handy than throwing it.It's very simple, really: from error codes to throwing is a shorter and easier path than vice versa. All you have to do is: try { auto amount = ThrowEof(io.readWithReturningEof(buf)); useData(buf, amount); } catch (Eof e) { /* do smth */ } ThrowEof is an identity function (see? the identity function I discussed a while ago wasn't that silly...) that returns whatever goes through it, not before checking for -1 and throwing if that's the case. One could also write a converse function ThrowProtect that does the opposite, but it's less clear and less efficient. Andrei
Feb 12 2007
Andrei Alexandrescu (See Website For Email) wrote:All you have to do is: try { auto amount = ThrowEof(io.readWithReturningEof(buf)); useData(buf, amount); } catch (Eof e) { /* do smth */ } ThrowEof is an identity function (see? the identity function I discussed a while ago wasn't that silly...) that returns whatever goes through it, not before checking for -1 and throwing if that's the case.That is a nice. I'll have to use that in my code.
Feb 13 2007
Dawid Ciężarkiewicz wrote:I've just asked Kris why mango is not throwing Eof in it's I/O operations instead of returning it. After short discusion he told me to ask about your opinons on NG (probably to stop me from distrupting him ;) ). So here am I. Two versions of same functionality. SomeIOClass { /* throws Eof, 0 == nothing available */ return uint readWithThrowingEof(void[] buf); /* -1 == eof, 0 == nothing available */ return int readWithReturningEof(void[] buf); } Which is better? I've always thought about returning Eof as an workaround when you can't throw it or it is too costly. Like in C. I mean: try { auto amount = io.readWithThrowingEof(buf); useData(buf, amount); } catch (Eof e) { /* do smth */ } Isn't any worse than: auto amount = io.readWithReturningEof(buf); if (ammount >= 0) { useData(buf, amount); } else if (ammount == -1) { /* do smth */ }In fact, the first one better. But only because the lack of typos :P. (ammount != amount)6 lines vs. 6 lines But when dealing with multiple reads, try block is _much_ better. In ideal situation you can only have one try {} catch {} and just read, use, read, use etc. I can come with many examples where catching/throwing Eof is more flexible both for implementator and library user and the difference is BIG. Especialy in D with great exception support. But are there cases where readWithReturningEof is better? Can someone give me a snippet that we could discuse on? I really have no idea where returning magical value Eof could be more handy than throwing it.You say multiple reads is much better with a try block? (And you use line count as a metric?) Let's read until end of file: --- int amount; while ((amount = io.readWithReturningEof(buf)) != EOF) { useData(buf, amount); } --- vs. --- try { while (true) { auto amount = io.readWithThrowingEof(buf); useData(buf, amount); } } catch (Eof e) { } --- 4 lines vs 7 lines, and one less indentation level when not using try blocks. I prefer the first one.
Feb 12 2007
Frits van Bommel wrote:You say multiple reads is much better with a try block? (And you use line count as a metric?)As was thinking about multiple reads in the code. Like: auto data = read(buf); auto dec = make_decision(data, buf); switch (dec) { case Dec.FIRST: /* read more */ auto data = read(buf); case Dec.SECOND: /* etc etc */ auto data = read(buf); } Of course real code is not that simple, but I hope this will clarify what I mean.Let's read until end of file: --- int amount; while ((amount = io.readWithReturningEof(buf)) != EOF) { useData(buf, amount); } --- vs. --- try { while (true) { auto amount = io.readWithThrowingEof(buf); useData(buf, amount); } } catch (Eof e) { } --- 4 lines vs 7 lines, and one less indentation level when not using try blocks. I prefer the first one.Yes, the first one is a little better. But mostly because throwing everyting into while statment. Although I must admit - this is such case where returning is more handy then throwing. Frits van Bommel scores. :)
Feb 13 2007
Dawid Ciężarkiewicz wrote:Kristian Kilpi has given me an idea: uint amount; while (io.notInEof()) { amount = io.readWithThrowingEof(buf); useData(buf, amount); } With inlining this code should be as fast as:try { while (true) { auto amount = io.readWithThrowingEof(buf); useData(buf, amount); } } catch (Eof e) { }int amount; while ((amount = io.readWithReturningEof(buf)) != EOF) { useData(buf, amount); }and is in at the cost of one line far more readable IMO. Io.notInEof() is not a problem - all implementation will have to have it probably. It's worth noting that replacing readWithThrowingEof with readWithReturningEof in this code will not change anything. So in such simple snippet of code we could have a loop that could do the same for both readWithThrowingEof and readWithReturningEof without difference. If you have no comments I will have to take back your point for snippet in which returning is better throwing. :>
Feb 13 2007
Reaching the eof is not an error, it is the expected behaviour. An exception shall only be thrown as an "exception", right? I think, a program shall not go through catch blocks in the normal case. An exception can lead to a big overhead (gathering data for stack trace?) or while debugging one might break at the next throw 4 symbol. To catch programming errors, ignoring the EOF symbol, we can throw the Exception if the read function is called again.
Feb 12 2007
Frank Benoit (keinfarbton) wrote:Reaching the eof is not an error, it is the expected behaviour. An exception shall only be thrown as an "exception", right? I think, a program shall not go through catch blocks in the normal case.I personaly have always wondered while people are thinking about exceptions like errors. This is of course talking about naming and theory, but it make big influence in code being created. Case One: Where an error isn't exception. Little naive, but still: /* returns last error */ int getErrno(); This function always returns an error. So error isn't exceptional at all. :) Less naive: /* returns: * true = everyting was ok * false = something went bad */ bool useData(char[] data); Here error isn't an exception, because function returns status of operation - error or not. Error is natural way that sometimes this function end. Not exceptional at all. In some cases useData can return error 100% of the time. Case Two: Where exception isn't error. /* Returns: amount of read data */ uint read(void[] buf); Here function returns amount of read data. This funtion could transfer gigabytes of data and Eof for single file/socket descriptor should happen only once. In fact eof can hardly be named anything else then exception for our code. We all know that Eof will happen one day, but it is really exception - normal program flow should be changed and everything changes because of that Eof.An exception can lead to a big overhead (gathering data for stack trace?) or while debugging one might break at the next throw 4 symbol.Yes. Indeed. So speed reasons are valid reasons to sacrifice exception and use an workaround like magic return value in some cases. *But* if exception is exceptional (like it should) then speed of _throwin_ exception shouldn't be considered. Only the speed of normal operation should be calculated. And not having to compare magic value everytime is speedup. I don't know if code in try {} block has any slowdown but if not then I'd expect using Exceptions to signal exceptions to be faster then using magic return values.
Feb 13 2007
On Tue, 13 Feb 2007 03:46:31 +0200, Dawid Ciężarkiewicz <dawid.ciezarkiewicz asn.pl> wrote:I've just asked Kris why mango is not throwing Eof in it's I/O operations instead of returning it. After short discusion he told me to ask about your opinons on NG (probably to stop me from distrupting him ;) ). So here am I. Two versions of same functionality. SomeIOClass { /* throws Eof, 0 == nothing available */ return uint readWithThrowingEof(void[] buf); /* -1 == eof, 0 == nothing available */ return int readWithReturningEof(void[] buf); } Which is better? I've always thought about returning Eof as an workaround when you can't throw it or it is too costly. Like in C. I mean: try { auto amount = io.readWithThrowingEof(buf); useData(buf, amount); } catch (Eof e) { /* do smth */ } Isn't any worse than: auto amount = io.readWithReturningEof(buf); if (ammount >= 0) { useData(buf, amount); } else if (ammount == -1) { /* do smth */ } 6 lines vs. 6 lines But when dealing with multiple reads, try block is _much_ better. In ideal situation you can only have one try {} catch {} and just read, use, read, use etc. I can come with many examples where catching/throwing Eof is more flexible both for implementator and library user and the difference is BIG. Especialy in D with great exception support. But are there cases where readWithReturningEof is better? Can someone give me a snippet that we could discuse on? I really have no idea where returning magical value Eof could be more handy than throwing it.Reaching EOF is not an error, of course, but reading while at EOF should be IMO. For example, all the bytes are read from a file: File f; while(f.isNotEnd()) buf ~= f.read(); No exception handling is required because we don't make assumptions about the contents of the file. File f; try { width = f.readInt(); //read an integer (4 bytes) stored in binary format height = f.readInt(); ... } catch() {...} Here we are assuming that the file contains (at least) 8 bytes. If the file was broken, then an exception tells that nicely.
Feb 13 2007
Kristian Kilpi wrote:Reaching EOF is not an error, of course, but reading while at EOF should be IMO.I see that your talking about something more then just error - exception thing which I dissagree (see in reply to Frank Benoit's post). I think it's quite natural that if file/socket is in Eof but in it's buffer there is still some unread data then read should first return that data and then - where there is nothing to return and will not be because file/socket connection has ended - Eof should be thrown. In fact if we want the code of: return uint readWithThrowingEof(void[] buf); return int readWithReturningEof(void[] buf); behave the same then both readWithReturningEof and readWithThrowingEof can not signalise Eof until all data were returned normaly. So that all your code will work like it should. In fact your've just pointed out additional advantage of throwing Eof instead of returning it. (...)For example, all the bytes are read from a file: File f; while(f.isNotEnd()) buf ~= f.read(); No exception handling is required because we don't make assumptions about the contents of the file.(...) Like in your code - if someone don't want to use try { } catch he will probably don't have to. Thanks. :)
Feb 13 2007