Dear Marc and Gambit community,<div><br></div><div>Here's a reflection on Gambit's IO routines' use of exceptions and a proposition for a tweak. For context, please check the previous email. Here we go:</div><div>



<br></div><div><br></div><div><br></div><div>I've come to relate to exceptions as a suitable medium pretty much solely for conveying an error state that requires manual administrator/programmer intervention.</div><div>



<br></div><div>Exceptions to the "solely" would be if there's some rare invocation of some routine, where a catch-all "it failed" kind of result would be satisfactory for error handling.</div><div>


<br></div><div><br></div><div>Thus, for instance if you make a laboratory project of connecting one computer to another and suddenly a <font face="courier new, monospace">read-u8</font> operation fails, that's a good reason to throw an exception. But, if you do <font face="courier new, monospace">read-u8</font>:s all the time in a context where some of them are expected to fail, I suggest the view that making that result in an exception is a terrible idea because of the reasons below.</div>


<div><br></div><div><div><br></div><div>So to sum up, Gambit's IO routines currently throw a quite wide variety of exceptions. At least a bunch of them essentially convey the same thing as a <font face="courier new, monospace">#f</font> or <font face="courier new, monospace">#!eof</font> result would have done.</div>


</div><div><br></div><div><br></div><div><br></div><div><b>Lots of cases when exception on IO error is a bad idea</b></div><div>A typical example of when this makes a difference, is when you want to make some IO work in Gambit, where some form of eof-like IO failure is an expected outcome. Examples:</div>


<div><br>
</div><div> * <font face="courier new, monospace">read-u8</font> from a TCP port that may or may not be closed now</div><div><br></div><div> * <font face="courier new, monospace">write-subst</font><font face="courier new, monospace">ring</font> to a TCP port that may or may not be closed now</div>


<div><br></div><div> * A HTTP request, in particular if it's to a host that's not under your control</div><div><br></div><div><br></div><div>All these calls cannot be wrapped individually in <font face="courier new, monospace">with-exception-catcher</font> blocks, you'd need a 1Thz core for per-byte reading of large amounts of data with each <font face="courier new, monospace">read-u8</font> wrapped in a <span style="font-family:'courier new',monospace">with-excepti</span><span style="font-family:'courier new',monospace">on-catcher</span> to not be too expensive, so my best understanding today is that the locations in Gambit's runtime that currently always produce exceptions in these cases, would benefit of a tweak:</div>



<div><br></div><div><br></div><div><b>What about: Introduce a global parameter object that introduces the option of <font face="courier new, monospace">#f</font>/<font face="courier new, monospace">#!eof</font> result instead of exception on IO error</b></div>


<div>As to keep code simple and effective, I would propose the introduction of a global parameter object <font face="courier new, monospace">io-prefer-eof-result-to-exception</font> to control this behavior, and perhaps one or two more global parameters to be assigned detailed error info in the event of io error.</div>



<div><br></div><div>Whenever a user needs to use IO with performance and in a might-fail context, he/she just switches this parameter to #t.</div><div><br></div><div>What's important is that IO can be done at high performance when it works. Unlike individual invocations wrapped in <font face="courier new, monospace">with-exception-catcher</font>, the presence of a parameter value has no overhead on individual procedure invocations. IO operation failures are extremely rare compared to IO operation successes (maybe 1:10,000), so the error handling code will be executed quite rarely and thus unwrapping of a parameter object is a no brainer expense in the context.</div>



<div><br></div><div><br></div><div>As to get to this suggestion, I experimented over a long period with <font face="courier new, monospace">with-exception-catcher</font> and with extracting Gambit<i> </i>IO routine code as to make custom exception-safe variants of them, this lead to the understanding that that cannot be reliably done, and involves copying of so much code that it's by far better to make a Gambit patch for this in the first place anyhow.</div>



<div><br></div><div><br></div><div><b><font face="courier new, monospace">#f</font> preferable over <font face="courier new, monospace">#!eof</font> as IO operation return value in case of EOF due to its more central position in the type system?</b></div>


<div>Last, there is some <font face="courier new, monospace">#!eof</font> returning in case of EOF already in Gambit's IO API. I have the impression that it's not completely consistent.</div>
<div><br></div><div>It's struck me that <font face="courier new, monospace">#!eof</font> not is so universal as EOF signal afterall: In a great many cases, <font face="courier new, monospace">#f</font> would be better due to its role in the type system - to do meaningful stuff with <font face="courier new, monospace">#!eof</font> you need to typecast it to boolean (i.e. <font face="courier new, monospace">(eq? result-value #!eof)</font>) to do anything meaningful with it anyhow, and all the regarded procedures never throw <font face="courier new, monospace">#f</font> within their current definition anyhow.</div>



<div><br></div><div>Because of this at most or all of</div><div><br></div><div><span style="font-family:'courier new',monospace">     read-subu8vector        read-substring           read-u8           read-char  peek-char read-line</span></div>


<div><font face="courier new, monospace">     write-subu8vector       write-substring          write-u8          write-char</font></div><div><font face="courier new, monospace">     force-output            close-input-port         close-output-port close-port</font></div>


<div><font face="courier new, monospace">     input-port-timeout-set! output-port-timeout-set!</font></div><div><br></div><div>would do better with <font face="courier new, monospace">#f</font> than <font face="courier new, monospace">#!eof</font> as return value to signal EOF.</div>


<div><br></div><div><br></div><div><b>Preliminary thought about next step: Make a patch and when it's mature, include it in the Gambit repo</b></div><div>Preliminarily I think this would be a good idea to pursue by making a Gambit patch that incorporates this functionality, and when it's mature, incorporating that patch into Gambit's master branch.</div>


<div><br></div><div>The value of having it in the master branch is that this way, Gambit-based libraries such as a HTTP client, can be written in the coding style that follows from this, which would clean up the code *alot* and calibrate design decisions in an advantageous direction:</div>


<div><br></div><div>Basically, error handling is done more explicitly but is much more specific - which is completely OK for IO-dense code for real world use, as this is what that kind of code does effectively anyhow - and there's some kind of performance increase.</div>


<div><br></div><div><br></div><div><br></div><div>Please feel free to share any thoughts you have on this topic, what do you say about the idea?</div><div><br></div><div><br></div><div><br></div><div>Best regards,</div><div>


Mikael</div><div><br></div>