dtonhofer

dtonhofer

Functional Programming in Java, Second Edition: Chapter 10 - Much too hard on exceptions, some thoughts

Just some thoughts on being hard on exceptions in functional languages.

On p. 167 we read:

Functional style code is amazing, concise, less complex, and easy to work with…until we hit exception handling. Exception handling is fundamentally an imperative style of programming idea. Throwing exceptions is incompatible with functional programming.

I beg to differ. There seems to be a strong feeling about this as the affirmation. It may be ugly but it’s not fundamentally a problem

Exception handling is fundamentally an imperative style of programming idea. Exception handling and functional programming are incompatible

is repeated on page 171. But in fact, a functional language - which in principle has no side effect - would have rather clean semantics regarding exceptions, would it not: just dump all the ongoing computation made since the nearest relevant “catch”. There would not even be a need to worry about anything else, like cleanup through finally blocks. As data structures in functional languages are supposed to be immutable, one would not even have to worry about such structures being left in some intermediate, improper state.

Furthermore we read:

You are not allowed to throw a checked exception from the functional pipeline.

But this is a problem of how functional pipelines have been defined in Java - the syntax does not allow it. It is not a fundamental problem. The fact that one is allowed to throw unchecked exceptions as normally (in fact, that cannot be avoided) indicates as much.

Here is some very interesting commentary on this:

We read at the above:

The simple answer to your question is: You can’t [throw checked exceptions from a stream pipeline], at least not directly. And it’s not your fault. Oracle messed it up. They cling on the concept of checked exceptions, but inconsistently forgot to take care of checked exceptions when designing the functional interfaces, streams, lambda etc. That’s all grist to the mill of experts like Robert C. Martin who call checked exceptions a failed experiment.

Going further in the book on p.167:

Don’t throw a runtime exception either. Sure, the compiler does not stop you from doing so, but you’ll abruptly end the functional pipeline processing and the previously processed data may be lost.

And on p.168:

The critical question we have to ask is what happens when an exception is thrown in the middle of processing a list of IATA codes. Exceptions blow up the call stack—plain and simple. If you carefully examine the code, you’ll see we are not catching the exception anywhere. So, it will result in abrupt termination of the program.

But that is the whole idea. You do want to discard (rather than blow up) all the contexts of the call stack that have become invalidated by the exception: everything up to the catch. It happens in all cases where one “throws”, whether in a stream pipeline or elsewhere. The one problem is that there is no nice place to set up “finally” handlers in a pipeline, but then again, resources should be opened & closed around the pipeline, not inside.

Examples:

ML has exceptions:

https://courses.cs.washington.edu/courses/cse341/04wi/lectures/10-ml-exceptions.html

Clojure has exceptions, they are exactly the JVM exceptions of course (probably slight different in ClojureScript, but I never looked into this)

https://clojuredocs.org/clojure.core/try

Scheme has exceptions

https://courses.cs.washington.edu/courses/cse341/04wi/lectures/15-scheme-continuations.html

Even languages with an unusual (but very powerful) model of computation like Prolog can have exceptions (although not in the - quite ancient - ISO Prolog standard), here is SWI-Prolog:

https://www.swi-prolog.org/pldoc/man?predicate=throw/1

As long as there is a concept of “a tree of computations” than can be torn down an rolled back, you can have them but: the meaning of “throwing an exception” may mesh inelegantly with the language and lead to various restrictions. And one always has to handle the two aspects in one’s head: what the program computes and how it is actually evaluated by the machine, virtual or otherwise. One could look at this as another example of a “leaky abstraction”: the state machine embedded in a real, failing world, peeks through the abstraction of a functional language exisiting in an idealistic universe layered on top.

The Monadic approach

When applied to stream pipelines, this is “Dealing with it Downstream”

The “Monadic” approach seems to be exactly the one promoted in Chapter 10. Here we create a construct similar to Java’s Optional<T> carrying either the result of a computation or information about the exceptional condition that occurred. On page 173, it is said that “we need a Union Type”, which is looking at the problem from the implementation side of course. We need an Exceptional<T>, here called Try<T>.

If a stage in the pipeline receives a Failure instead of receiving a Success, the function in that stage will merely pass along that failure downstream without processing.

In other words, applying a function to an instance of type Try<T> behaves like the identity.

Haskell seems to handle exceptions “the monadic way”

https://wiki.haskell.org/Exception

In

Govindarajan, R. (1993). Exception handlers in functional programming languages. IEEE Transactions on Software Engineering, 19(8), 826–834. doi:10.1109/32.238585

which promotes the same idea (“a shielded value”) but also adds “cure handlers” to manage locally-fixable problem, I found this text:

A key issue in program construction is robustness. Software reliability can be achieved by the judicious use of fault-tolerant tools. Exception handling is one of the two techniques used for developing reliable software.

Bretz and Ebert identify two problems in supporting exception handling constructs in functional programming. An exception, in imperative languages, is treated as a means of effecting a control transfer. Hence, there is a fundamental conflict between the functional approach followed in functional languages and the control flow-oriented view of exceptions.

Due to this, exceptions in functional languages can result in nondeterministic behavior of the FP program. For example, if there are two exception points inside a given function, the result of parallel evaluation of the function could be different, depending on which exception is raised first. This problem has been considered as intrinsic to incorporating exceptions in functional languages. Languages ML and ALEX circumvent this problem by proposing sequential execution for FP. Such a restriction is severe and is essentially required because the control flow view of exceptions has been carried through to functional languages. We discard this view and define the semantics of FP functions operating on exception objects without imposing any restriction on the execution.

Secondly, exception handling might cause side effects in expressions and hence might violate the property of referential transparency. Proposed solutions suggest the association of an environment with the functions. But in our case, discarding the conventional control flow view of exception solves this problem naturally.

Reeves et al. point out that embedding exception handling constructs in lazy functional languages can transform nonstrict functions into hyper-strict functions. (…) This is because both subexpressions need to be evaluated to determine whether or not they raise any exception. Reeves et al. claim the transformation of nonstrict actors into hyper-strict actors is due to the up-propagation of signals through nonstrict operators. To overcome this problem, the notion of down-propagation and firewalls has been defined (…). In this paper, however, we argue that it is not the up-propagation, but the persistent nature of exception values that causes the above problem.

As previously mentioned, Philip Wadler on this in a quite mathematical notation to express M<T> in “Monads for Functional Programming”, which can be found here:

https://homepages.inf.ed.ac.uk/wadler/topics/monads.html

Popular Pragmatic Bookshelf topics Top

belgoros
Following the steps described in Chapter 6 of the book, I’m stuck with running the migration as described on page 84: bundle exec sequel...
New
raul
Hi Travis! Thank you for the cool book! :slight_smile: I made a list of issues and thought I could post them chapter by chapter. I’m rev...
New
HarryDeveloper
Hi @venkats, It has been mentioned in the description of ‘Supervisory Job’ title that 2 things as mentioned below result in the same eff...
New
New
brian-m-ops
#book-python-testing-with-pytest-second-edition Hi. Thanks for writing the book. I am just learning so this might just of been an issue ...
New
brunogirin
When I run the coverage example to report on missing lines, I get: pytest --cov=cards --report=term-missing ch7 ERROR: usage: pytest [op...
New
akraut
The markup used to display the uploaded image results in a Phoenix.LiveView.HTMLTokenizer.ParseError error. lib/pento_web/live/product_l...
New
taguniversalmachine
Hi, I am getting an error I cannot figure out on my test. I have what I think is the exact code from the book, other than I changed “us...
New
rainforest
Hi, I’ve got a question about the implementation of PubSub when using a Phoenix.Socket.Transport behaviour rather than channels. Before ...
New
gorkaio
root_layout: {PentoWeb.LayoutView, :root}, This results in the following following error: no “root” html template defined for PentoWeb...
New

Other popular topics Top

AstonJ
A thread that every forum needs! Simply post a link to a track on YouTube (or SoundCloud or Vimeo amongst others!) on a separate line an...
New
ohm
Which, if any, games do you play? On what platform? I just bought (and completed) Minecraft Dungeons for my Nintendo Switch. Other than ...
New
wolf4earth
@AstonJ prompted me to open this topic after I mentioned in the lockdown thread how I started to do a lot more for my fitness. https://f...
New
mafinar
Crystal recently reached version 1. I had been following it for awhile but never got to really learn it. Most languages I picked up out o...
New
AstonJ
If you get Can't find emacs in your PATH when trying to install Doom Emacs on your Mac you… just… need to install Emacs first! :lol: bre...
New
New
First poster: bot
The overengineered Solution to my Pigeon Problem. TL;DR: I built a wifi-equipped water gun to shoot the pigeons on my balcony, controlle...
New
First poster: bot
Large Language Models like ChatGPT say The Darnedest Things. The Errors They MakeWhy We Need to Document Them, and What We Have Decided ...
New
DevotionGeo
I have always used antique keyboards like Cherry MX 1800 or Cherry MX 8100 and almost always have modified the switches in some way, like...
New
CommunityNews
A Brief Review of the Minisforum V3 AMD Tablet. Update: I have created an awesome-minisforum-v3 GitHub repository to list information fo...
New

Latest in Functional Programming in Java, Second Edition

Functional Programming in Java, Second Edition Portal

Sub Categories: