The Artima Developer Community
Sponsored Link

Weblogs Forum
Coffee with James Ward

11 replies on 1 page. Most recent reply: Aug 24, 2011 7:37 PM by winston kodogo

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 11 replies on 1 page
Bruce Eckel

Posts: 875
Nickname: beckel
Registered: Jun, 2003

Coffee with James Ward (View in Weblogs)
Posted: Jul 22, 2011 10:51 AM
Reply to this message Reply
Summary
James is in Crested Butte for the month because his wife is doing a medical residency rotation here. This morning we had a couple of epiphanies over coffee.
Advertisement

There seems to be no substitute for hanging out in a relaxed atmosphere and batting around ideas. There should be a lot more of that during next week's Programming Summer Camp.

1. The Definition of "Enterprise Software"

This one has been bugging a lot of us for years. The best anyone could come up with is, "Uh ... it costs a lot?" but that doesn't really tell you anything.

There is one thing that does appear to differentiate enterprise software from consumer/small business/off-the-shelf software, and that's customization. It seems that if you're talking about enterprise software, you can never buy something off the shelf that just works -- customization is always involved. In fact for a lot of enterprise software, you can pay heavily for the "basic package" that doesn't do anything, then you pay 3 or 4 times as much (or sometimes more) before it actually does something useful.

You can look at software as a spectrum starting from "no customization" (consumer) at one end to "does nothing without customization" (enterprise) at the other.

What do you think?

2. Exception Bizarro World

James has been trying to create some very straightforward teaching examples using JDBC, and keeps getting foiled by checked exceptions. He pointed me to Howard Lewis Ship's recent post The Tragedy of Checked Exceptions (in the comments, there's an indirect link to some of my years-ago writings on the subject). In particular, James was very frustrated by the all the hoops he had to jump through in order to do something that ought to be simple. Even in the finally block he's forced to put more try-catch clauses because closing the connection can also cause exceptions. Where does it end? To do something simple you're forced to jump through hoop after hoop.

Then we started talking about the Go programming language, which I've been fascinated with lately because Rob Pike et. al. have clearly asked a lot of very incisive and fundamental questions about language design. Basically, they've taken everything we've started to accept about languages and asked, "Why?" about each one. Learning this language (which I've only started) really makes you think and wonder.

My impression is that the Go team has decided not to make any assumptions and to evolve the language only when it is clear that a feature is necessary. They don't seem to worry about doing changes that break old code -- they created a rewriting tool so that if they make such changes it will rewrite the code for you. This frees them to make the language an ongoing experiment to discover what's really necessary rather than doing Big Upfront Design.

One of the most interesting decisions they made is to leave out exceptions altogether. You read that right -- they aren't just leaving out checked exceptions. They're leaving out all exceptions.

The alternative is very simple, and at first it almost seems C-like. Because Go incorporated tuples from the beginning, you can easily return two objects from a function call:

result, err := functionCall()

(The ':=' tells Go that result and err are being defined here and that their types should be inferred).

That's it: for each call you get back the result object and an error object. You can check the error right away (which is typical, because if something fails it's unlikely you'll want to blithely go on to the next step), or check it later if that works.

At first this seems primitive, a regression to ancient times. But so far I've found that the decisions in Go are very well considered, and worth pondering. Am I simply reacting because my brain is exception-addled? How would this affect James' problem?

During our coffee conversation, it occurred to me that I've always seen exception handling as kind of a parallel execution path. If you hit an exception, you jump out of the normal path into this parallel execution path, a kind of "bizarro world" where you are no longer doing the things that you wrote, and instead jumping around into catch and finally clauses. It's this alternate-execution-path world that causes the problems that James is complaining about!

James creates an object. Ideally, object creation does not cause potential exceptions, but if it does you have to catch those. You have to follow creation with a try-finally to make sure cleanup happens (the Python team realized that cleanup is not really an exceptional condition, but a separate problem so they created a different language construct so as to stop conflating the two). Any call that causes an exception stops the normal execution path and jumps (via parallel bizarro-world) to the catch clause.

One of the fundamental assumptions about exceptions are that we somehow benefit by collecting all the error handling code at the end of the block rather than handling errors at the point they occur. In both cases we want to stop normal execution, but exception handling has an automatic mechanism that throws you out of the normal execution path, jumps you into bizarro-parallel-exception world, then pops you back out again in the right handler.

Jumping into bizarro world is what causes the problems for James, and it adds more work for all programmers: because you can't know when something is going to happen (you can slip into bizarro world at any moment), you have to add layers of try blocks to ensure that nothing slips through the cracks. You end up having to do extra programming in order to compensate for the exception mechanism (It feels something like the extra work you have to do to compensate for shared-memory concurrency).

The Go team made the bold move of questioning all this, and saying, "Let's try it without exceptions and see what happens." Yes, this means that you're typically going to handle errors where they occur rather than clumping them all at the end of a try block. But hmm, that means that code that is about one thing is localized -- maybe not so bad. It also means you might not be able to easily combine common error-handling code (unless you identified that common code and put it into a function, also not so bad). But it definitely means you don't have to worry about having more than one possible execution path and all that entails.

I'm going to be watching the Go experiment closely to see how it pans out; for me, "success" means code is easier to write and read (I hope to start writing some experimental Go code in the near future).


Mike Slinn

Posts: 4
Nickname: mslinn
Registered: Dec, 2004

Re: Coffee with James Ward Posted: Jul 22, 2011 5:36 PM
Reply to this message Reply
Java 7's exception handling may please you:
http://java.about.com/b/2010/05/04/improved-exception-handling-in-jdk-7.htm

robert young

Posts: 361
Nickname: funbunny
Registered: Sep, 2003

Re: Coffee with James Ward Posted: Jul 23, 2011 6:34 AM
Reply to this message Reply
-- But it definitely means you don't have to worry about having more than one possible execution path and all that entails.

Reminds me of the religious war over having only one return statement. I am among those who thinks that's a Good Idea; so did our grandpappy COBOL coders, mostly. I guess that's why java coders, for example, strew them like appleseeds; if it were smart for grandpappy, it must actually be dumb. I get the irony: COBOL in database applications is a mess which I abhor.

Here: http://www.leepoint.net/JavaBasics/methods/method-commentary/methcom-30-multiple-return.html

Which includes a link to a Bruce posting that multiple returns is a Good Thing. Which is it??

There is also a link to a post which argues that single return leads to clarity. The author of the cited post acknowledges the irony.

Discuss among yourselves.

John Eikenberry

Posts: 1
Nickname: eikenberry
Registered: Jul, 2011

Re: Coffee with James Ward Posted: Jul 23, 2011 11:09 AM
Reply to this message Reply
>They're leaving out all exceptions.

This is incorrect.

http://blog.golang.org/2010/08/defer-panic-and-recover.html

If you read the above blog entry you will see that go does have a version of exceptions. They are just implemented differently. Personally I think it captures most of the benefits of exceptions while offering some interesting new possibilities.

Vincent O'Sullivan

Posts: 724
Nickname: vincent
Registered: Nov, 2002

Re: Coffee with James Ward Posted: Jul 24, 2011 1:34 AM
Reply to this message Reply
> for each call you get back the result object
> and an error object. You can check the error right away
> (which is typical, because if something fails it's
> unlikely you'll want to blithely go on to the next step),
> or check it later if that works.

Putting checked exceptions to one side (because that's a different - and distracting - issue to comparing similar exception handling in language A to that in language B)...

Other than syntax, this is no different to exception handling in Java. I can't see why this Go code:
result, err := functionCall()
if err != nil {
    handleError(err)
} else {
   handleResult(result)
}
is better than this Java code:
try {
    handleResult(functionCall());
} catch(Exception err) {
    handleError(err);
}
I've never used Go, so I'm doubtless missing something. Could you explain what?

Edit: As I was about to hit the <Post> button, I noticed that the Java code above actually trapped errors from both function calls, whereas the Go code would require extra error handling for the handleResult() function. Doubtless, a rewrite from a Go programmer would correct that but I'm still am not sure why the "Go" style of error handling is better rather than different.

Aivar Annamaa

Posts: 2
Nickname: aivara
Registered: Oct, 2010

Re: Coffee with James Ward Posted: Jul 24, 2011 6:38 AM
Reply to this message Reply
> all the error handling code at the end of the block

Most of my error handling code is many stackframes upwards and Java style exceptions (except checked exception system) work great to support this.

Michael Chermside

Posts: 17
Nickname: mcherm
Registered: Jan, 2004

Re: Error codes instead of Exceptions Posted: Jul 27, 2011 1:18 PM
Reply to this message Reply
I certainly agree that checked exceptions were an experiment in Java that failed. They have nice behavior on toy-sized projects and poor behavior on large projects.

But I think that exceptions have a strong advantage over error codes. (In fact, checked exceptions fail exactly because they break this feature.) That advantage is the ability to IGNORE the problem.

If you are going to catch and handle an exception, then it doesn't matter much whether you use an error code or an exception.

int tryCatchWhichIsHandled() {
    int result;
    try {
        result = callSomeFunction();
    } catch(UnusualException err) {
        handleError(err);
        result = DEFAULT_VALUE;
    }
    return result;
}


int errorCodeWhichIsHandled() {
    int result, err;
    result, err = callSomeFunction();
    if (err) {
        handleError(err);
        result = DEFAULT_VALUE;
    }
    return result;
}


But the difference comes if you do NOT have a way of handling the error. I have found that the best practice with exceptions is the following: if your code can FIX the problem (try again, try a different approach, use a default value) or your code can REPORT the problem (warn the user, log an error), then you should catch the exception. Otherwise, you should NOT catch it, which means something higher up in the call stack will catch and handle it.

Furthermore, I find that the vast majority of the time, my code CANNOT fix or report the error -- most errors can't be fixed and most reporting happens at a certain layer in the application (which is written just once, so nearly all of the code is NOT that layer).

In what I claim is the most common case, an unchecked exception gives very clean code:

int exceptionNotHandled() {
    return callSomeFunction();
}


But unchecked exceptions are uglier:
int checkedExceptionNotHandled() throws UnusualException {
    return callSomeFunction();
}


... soon nearly EVERY method in your program is declared to throw UnusualException. (Or more likely, every method is declared to throw CommonExceptionAncestor, which is even less informative.)

Using error codes is actually WORSE than the unchecked exceptions. Here we see it in Java pseudocode that allows multi-argument returns:

(int, int) errorCodeNotHandled() {
    int result, err;
    result, err = callSomeFunction();
    return result, err;
}


Soon, nearly every method in your program has been modified to return two things: its value and an error code. Then you quickly figure out that numerical error codes don't carry enough information and you institute a convention that ALL methods MUST return 2 or more arguments, and the first argument is ALWAYS an Exception object. You have re-created exceptions, with much uglier syntax. If you think that errors should nearly always be handled near where they happen, then the error code approach makes sense (and so do checked exceptions!). But if you think (as I do) that most of the time errors should be handled someplace ELSE, then exceptions are much cleaner.

(It is, however, important to KNOW what exceptions might be happening so you can reason about whether your code should be handling it. Unchecked exceptions aren't very helpful there.)

Marko Loparic

Posts: 3
Nickname: markolopa
Registered: Jul, 2011

Re: Coffee with James Ward Posted: Jul 31, 2011 1:42 AM
Reply to this message Reply
> At first this seems primitive, a regression to ancient times.

Thanks a lot for another thought provoking article! I love the effort you do to question what we do on a daily basis! Having said that, I believe that there is one or two arguments missing to make to point that Go people's choice of no exception could be an interesting alternative to the exception mechanism we are used to. I have read your post twice, but I still see as an enormous "regression to ancient times" to be forced to handle the errors after each call. For me the number one advantage of using exceptions is the readability of the code. I absolutely don't want to mix the "what if the file name was wrong" considerations with the flow of my algorithm.

Cheers,
Marko

Bruce Eckel

Posts: 875
Nickname: beckel
Registered: Jun, 2003

Re: Coffee with James Ward Posted: Aug 4, 2011 1:23 PM
Reply to this message Reply
I haven't come to a conclusion about whether exceptions are or are not the best way to handle errors. However, I've found a lot of the other Go design decisions to be delightfully refreshing and so the fact that they didn't automatically put in exceptions makes me question the idea of exceptions and wonder if there might be a better way. I've lived with exceptions for so long (I started puzzling over them at their introduction in C++, when I was on the standards committee) that Go's decision made me realize I had only questioned checked exceptions, not exceptions themselves. So this is a new point to ponder.

I agree that being able to separate the exception handling from the origin of the exception seems like a useful idea. But when I first saw checked exceptions that seemed like a good idea, too, and I promoted it as such. So now I wonder if there isn't a better way, and perhaps Go is in the process of finding it (they clearly created the language to allow it to evolve).

winston kodogo

Posts: 2
Nickname: kodogo
Registered: Aug, 2011

Re: Coffee with James Ward Posted: Aug 23, 2011 7:11 PM
Reply to this message Reply
Re exceptions, some of we geriatric folk have always felt that they were a bad idea, for reasons clearly explained some years ago by Verity Stob.

Their absence in Go is no surprise - as recently as 2003 Rob Pike had this to say:


> (c) no need for explicit tests of function error
> returns

therefore subverting programming discipline.

> Basically, it's a way to impose order on chaos.

and replace it with a mysterious, hard to understand
mechanism with a tendency to overlay a program's
structure with confusing, noisy error-handling
details.

i'm not a fan of exceptions. good programming
can trump them every time; bad exception handling
can destroy a program. they're an interesting idea
but i judge them a failure.

-rob

Vincent O'Sullivan

Posts: 724
Nickname: vincent
Registered: Nov, 2002

Re: Coffee with James Ward Posted: Aug 23, 2011 11:56 PM
Reply to this message Reply
> i'm not a fan of exceptions. good programming
> can trump them every time;

Could you give an example of how you would handle an exception without 'exception handling'.

winston kodogo

Posts: 2
Nickname: kodogo
Registered: Aug, 2011

Re: Coffee with James Ward Posted: Aug 24, 2011 7:37 PM
Reply to this message Reply
> Could you give an example of how you would handle an
> exception without 'exception handling'.

Well, no. Could you give an example of an exception that needs to be thrown?

Flat View: This topic has 11 replies on 1 page
Topic: Odersky Explains Shared-Memory Concurrency Previous Topic   Next Topic Topic: ScalaTest 1.6.1.RC1 for Scala 2.9.0 Released

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use