www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Eof - to return or to throw?

reply Dawid =?UTF-8?B?Q2nEmcW8YXJraWV3aWN6?= <dawid.ciezarkiewicz asn.pl> writes:
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
next sibling parent reply "Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail erdani.org> writes:
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
parent Dawid =?UTF-8?B?Q2nEmcW8YXJraWV3aWN6?= <dawid.ciezarkiewicz asn.pl> writes:
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
prev sibling next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
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
parent reply Dawid =?UTF-8?B?Q2nEmcW8YXJraWV3aWN6?= <dawid.ciezarkiewicz asn.pl> writes:
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
parent Dawid =?UTF-8?B?Q2nEmcW8YXJraWV3aWN6?= <dawid.ciezarkiewicz asn.pl> writes:
Dawid Ciężarkiewicz wrote:

 try {
    while (true) {
       auto amount = io.readWithThrowingEof(buf);
       useData(buf, amount);
    }
 } catch (Eof e) {
 }


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:
 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
prev sibling next sibling parent reply "Frank Benoit (keinfarbton)" <benoit tionex.removethispart.de> writes:
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
parent Dawid =?UTF-8?B?Q2nEmcW8YXJraWV3aWN6?= <dawid.ciezarkiewicz asn.pl> writes:
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
prev sibling parent reply "Kristian Kilpi" <kjkilpi gmail.com> writes:
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. Example #2: 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
parent Dawid =?UTF-8?B?Q2nEmcW8YXJraWV3aWN6?= <dawid.ciezarkiewicz asn.pl> writes:
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