Smalltalker learns Java - observations
Thomas Gagne has some interesting observations about the differences in exception handling in Smalltalk and Java:
I was recently reading about Exceptions in Java and discovered they aren't resumable. You can't pick-up from where an exception was thrown. I began wondering how this might be possible in Java, but it would require a change to Java's syntax--or the language. Why?
Java doesn't support code blocks as objects. New functionality can't be introduced to blocks of code without changing the language itself. try/catch/finally is implemented as part of the language and not as a feature of an object.
Also, because Java as statically typed it would be nearly impossible to resume with a new value anyway since the "throw" command would have to be able to return a value--but since throw is a command it doesn't return values--and even if it did it would have to return the amorphous "object" which would then require down casting to be made useful. Even then it may be impossible to resume processing with an alternative primitive value.
So Java programs have to run while{}s outside their try{}catch{}s to correct something--which makes the granularity of what can be retried fairly large. Meaning, if there are side effects inside try{} they will either need to be reexecutable without additional (bad) effects or whatever they did will require undoing (or inoculation) inside the catch{}.
In Smalltalk, however, interesting features can be added to blocks and exceptions because they're objects, and object's behavior can be extended without subclassing and is possible in the first place because they aren't "final" nor closed in the base library.
Smalltalk is even neater now than it was a few weeks ago.





Comments
Explain?
[Gordon Weakliem] August 21, 2003 12:36:49.792
Explain this, please. This is really interesting and it'd definitely change the way I think about exceptions. The other day I wrote something about how libraries get misdesigned, for instance, the .NET HttpWebRequest/HttpWebResponse classes throw a WebException if the server returns anything other that a 200. So to handle that, you have to write a loop to handle recoverable errors like redirects, probably have a switch in your exception handler to do things like unsubscribe from a bad RSS feed. Also, if you're trying to open a file for exclusive access, you have to put a loop around a try {} catch (System.IO.IOException) {} and retry the file open if it failed because the file's locked. Can you give a simple example of what recoverable exception handling looks like in Smalltalk?
Re: Smalltalker learns Java - observations
[alan knight] August 21, 2003 13:19:58.114
Comment on Smalltalker learns Java - observations by alan knight
Another, perhaps even more fundamental, obstacle is that exception handling happens in fundamentally different ways.
In Smalltalk, exception handling proceeds in two stages. First, you walk up the stack, searching for a handler. Once you've found (or not found) one, you invoke the handler. If the handler doesn't resume, then at that point the stack gets unwound, ensure blocks run, and so forth. You can observe this if you put a halt inside an ensure, and a Transcript show: in the ensure block. Note that the Transcript updates only when you close or proceed the debugger.
In Java (and in C , and I expect in C#), exception handling is one phase. As you walk up the stack looking for a handler, you unwind the stack. So by the time you find a handler, the stack is gone, and there's no way you could resume.
Another manifestation of this is debugger behaviour. In Smalltalk, an unhandled exception puts you into the debugger. In Java, it throws you out of the debugger (I just about fell out of my chair the first time this happened to me). Java environments typically work around this by letting you put breakpoints into the constructors of the exception, but that has some ugly side-effects. It stops for any exception, not just unhandled ones, which can be very unpleasant if you are (like VisualAge code used to) throwing lots and lots of null pointer exceptions and catching them. Also, if you terminate a process that stopped on such a breakpoint, your "finally" code never runs.
These are fairly subtle points to explain, but make quite a significant difference in your ability to get things done.
Re: Explain?
[James Robertson] August 21, 2003 13:36:45.581
Comment on Explain? by James Robertson
Well, here's a simple example. Say we have a class T1 with an instance variable myVal which we have initialized to zero. Now posit a simple add method:
What happens is that when we have an exception, we can just assume an input value of 0 and add it. Now sure, this is a silly example. What I'm trying to show is a simple minded example without complexity. You can also do a #retryWith: - which replaces the exception handler block with a new one and tries the original code block again. The example above merely resumes with a new value - a value instead of the one produced by the exception. In VisualWorks, have a look at classs GeneralException, and at the actions method category. There's a wealth of possibilities there. What this allows you to do is do nifty exception handling without interrupting the flow of execution.
Re: Smalltalker learns Java - observations
[Navin] April 12, 2004 4:57:42.665
I'd be very interested to see resumable exceptions coupled with swapping threads (or LWPs as they are dealt with in linux) into dormant data structures. Here are the two bad solutions currently available: a. get a thread from the threadpool and use Blocking-IO to read() b. get a thread from the threadpool and use Non-blocking-IO to read(), creating a CharSequence wrapper over this inputstream, caching into some internal StringBuffer 's'. Whenever .charAt(int) is beyond s.length(), issue appropriate number of additional read()s, appending to s. If read() returns prematurely because input isn't ready, throw an Exception. Solution-a causes DoS attacks to cause huge numbers of threads to sit there like idiots sleeping. Solution-b requires a complete restart of any function wanting to use that string. E.g. if you want to read "^(GET|PUT) +(.*?) +HTTP/\d+\.\d+\r\n", then you have to pass the CharSequence to a regex util, and if Exception is thrown because input isn't ready to match the minimum needed characters, then we have to return the thread to threadpool without remembering /exactly/ where we left off. So when this worker restarts (presumably when a Selector notices input is ready again), it has to redo whatever it began before getting back to where it left off. This leads to kludge-solutions where we specifically encode HTTP hacks that index the last char of the CharSequence checked, and scan from there for \r\n before calling the regex api. What I'd LOVE, absolutely LOVE, LOVE, LOVE to see is the following: b. get a thread from the threadpool and use Non-blocking-IO to read(), creating a CharSequence wrapper over this inputstream, caching into some internal StringBuffer 's'. Whenever .charAt(int) is beyond s.length(), issue appropriate number of additional read()s, appending to s. If read() returns prematurely because input isn't ready, throws a ResumableException. (SO FAR, SAME as Solution-b) Now, the fun part: The thread catches this unhandled exception, and calls ResumableException.handle(InternalState). The implemented ResumablException in this case would have code to add the input to a central Selector with OP_READ and a Runnable attachment which gets a thread from the threadpool *Initialized to InternalState*. This solution-c would have the benefits of nonblocking solution-b (awesome reduction in thread ovherhead) while not having the nasty problem of how to resume operation (which blocking solution-a doesn't have to worry about since blocking routines will resume wherever you called them). PLEASE! Someone at Sun listen to this and find a way to have nonblocking APIs that are resumable ! I want to be able to "block" on read(), returning my thread to the threadpool and resume later once the selector deems the read() will succeed !!!!!