Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>There are two ways to think about exceptions. One way is to think of them as flow control: an exception changes the flow of execution of the program, making the execution jump from one place to another. A second way is to think of them as data: an exception is an information about the execution of the program, which can then be used as input to other parts of the program.</p> <p>The <code>try</code>/<code>catch</code> paradigm used in C++ and Java is very much of the first kind(*). </p> <p>If, however, if you prefer to deal with exceptions as data, then you'll have to resort to code such as the one shown. For the simple case, that's rather easy. However, when it comes to the functional style where composition is king, things start to get complicated. You either have to duplicate code all around, or you roll your own library to deal with it.</p> <p>Therefore, in a language which purports to support both functional and OO style, one shouldn't be surprised to see library support for treating exceptions as data.</p> <p>And note that there is oh-so-many other possibilities provided by <code>Exception</code> to handle things. You can, for instance, chain catch handlers, much in the way that Lift chain partial functions to make it easy to delegate responsibility over the handling of web page requests.</p> <p>Here is one example of what can be done, since automatic resource management is in vogue these days:</p> <pre><code>def arm[T &lt;: java.io.Closeable,R](resource: T)(body: T =&gt; R)(handlers: Catch[R]):R = ( handlers andFinally (ignoring(classOf[Any]) { resource.close() }) apply body(resource) ) </code></pre> <p>Which gives you a safe closing of the resource (note the use of ignoring), and still applies any catching logic you may want to use.</p> <p>(*) Curiously, Forth's exception control, <code>catch</code>&amp;<code>throw</code>, is a mix of them. The flow jumps from <code>throw</code> to <code>catch</code>, but then that information is treated as data.</p> <p><strong>EDIT</strong></p> <p>Ok, ok, I yield. I'll give an example. ONE example, and that's it! I hope this isn't too contrived, but there's no way around it. This kind of thing would be most useful in large frameworks, not in small samples.</p> <p>At any rate, let's first define something to do with the resource. I decided on printing lines and returning the number of lines printed, and here is the code:</p> <pre><code>def linePrinter(lnr: java.io.LineNumberReader) = arm(lnr) { lnr =&gt; var lineNumber = 0 var lineText = lnr.readLine() while (null != lineText) { lineNumber += 1 println("%4d: %s" format (lineNumber, lineText)) lineText = lnr.readLine() } lineNumber } _ </code></pre> <p>Here is the type of this function:</p> <pre><code>linePrinter: (lnr: java.io.LineNumberReader)(util.control.Exception.Catch[Int]) =&gt; Int </code></pre> <p>So, <code>arm</code> received a generic Closeable, but I need a LineNumberReader, so when I call this function I need to pass that. What I return, however, is a function <code>Catch[Int] =&gt; Int</code>, which means I need to pass two parameters to <code>linePrinter</code> to get it to work. Let's come up with a <code>Reader</code>, now:</p> <pre><code>val functionText = """def linePrinter(lnr: java.io.LineNumberReader) = arm(lnr) { lnr =&gt; var lineNumber = 1 var lineText = lnr.readLine() while (null != lineText) { println("%4d: %s" format (lineNumber, lineText)) lineNumber += 1 lineText = lnr.readLine() } lineNumber } _""" val reader = new java.io.LineNumberReader(new java.io.StringReader(functionText)) </code></pre> <p>So, now, let's use it. First, a simple example:</p> <pre><code>scala&gt; linePrinter(new java.io.LineNumberReader(reader))(noCatch) 1: def linePrinter(lnr: java.io.LineNumberReader) = arm(lnr) { lnr =&gt; 2: var lineNumber = 1 3: var lineText = lnr.readLine() 4: while (null != lineText) { 5: println("%4d: %s" format (lineNumber, lineText)) 6: lineNumber += 1 7: lineText = lnr.readLine() 8: } 9: lineNumber 10: } _ res6: Int = 10 </code></pre> <p>And if I try it again, I get this:</p> <pre><code>scala&gt; linePrinter(new java.io.LineNumberReader(reader))(noCatch) java.io.IOException: Stream closed </code></pre> <p>Now suppose I want to return 0 if any exception happens. I can do it like this:</p> <pre><code>linePrinter(new java.io.LineNumberReader(reader))(allCatch withApply (_ =&gt; 0)) </code></pre> <p>What's interesting here is that <strong>I completely decoupled the exception handling</strong> (the <code>catch</code> part of <code>try</code>/<code>catch</code>) <strong>from the closing of the resource</strong>, which is done through <code>finally</code>. Also, the error handling is a value I can pass on to the function. At the very least, it makes mocking of <code>try</code>/<code>catch</code>/<code>finally</code> statements much easier. :-)</p> <p>Also, I can combine multiple <code>Catch</code> using the <code>or</code> method, so that different layers of my code might choose to add different handlers for different exceptions. Which really is my main point, but I couldn't find an exception-rich interface (in the brief time I looked :).</p> <p>I'll finish with a remark about the definition of <code>arm</code> I gave. It is not a good one. Particularly, I can't use <code>Catch</code> methods such as <code>toEither</code> or <code>toOption</code> to change the result from <code>R</code> to something else, which seriously decreases the value of using <code>Catch</code> in it. I'm not sure how to go about changing that, though.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload