Re: [go-nuts] Palatable Exception Handling (v2)

676 views
Skip to first unread message

Patrick Mylund Nielsen

unread,
Jun 29, 2012, 3:31:27 PM6/29/12
to karl.p...@gmail.com, golan...@googlegroups.com
"Q: But nobody needs exceptions!
A: I have no intention of taking my nice python code base and doubling/tripling its size due to menial checks for all database, network, and filesystem calls (which the other devs will assuredly screw up).  You guys are out to lunch."

I like that you take the time to at least provide examples, but leading with this kind of snarky comment really does not help your argument.

I don't speak for the language designers, but Go's error handling is absolutely fundamental to the language, and I very much doubt that it will change. I also know that a very large group of Go users aren't missing exceptions at all, and in fact prefer Go's approach.

If you absolutely must have exceptions, use panic/recover. If those are not sufficient, maybe Go isn't the right language.

I really encourage you to read and write a few applications in Go, and giving thought to when it's best to use panic, and to return errors. I think you'll find that Go's approach to error handling is much nicer than it might seem right now.

On Fri, Jun 29, 2012 at 7:16 AM, <karl.p...@gmail.com> wrote:
Palatable Exception Handling V2

ex 1: Let parents handle it
rows = db.RunQuery(query)
print("No exception happened")


ex 2: I'll handle a certain exception
rows, e = db.__RunQuery(query)
handle(e) {
    if e != nil and db.IsDuplicateError(e) {
        print("eh, no big deal")        
        e.handled = True
    }
}
print("No exception other than Duplicate happened")


ex 3: I'll handle / swallow all exceptions
rows, e = db.__RunQuery(query)
handle(e) {
    if e != nil {
        print("we had an oopsies")        
        e.handled = True
    }
}
print("I'm indefatigable, hahaha!")


Q: What does the leading __ do?
A: It makes any function return the exception instead of raise it.  

Q: What does the handle() { }  do?
A: It makes it hard to accidentally swallow something you didn't mean to.  You have to explicitly say e.handled = True (i.e. hit the snooze button).  Otherwise, a non-nil exception that wasn't handled gets re-raised when the block ends.

Q: But what's stopping you from not using a handle() block at all, and checking the exception badly by hand?
A: Nothing.  However, static analysis could warn on this (exception object never passed to any handle() block).  Could be a style rule for large projects.

Q: But nobody needs exceptions!
A: I have no intention of taking my nice python code base and doubling/tripling its size due to menial checks for all database, network, and filesystem calls (which the other devs will assuredly screw up).  You guys are out to lunch.

- Karl


DisposaBoy

unread,
Jun 29, 2012, 4:20:01 PM6/29/12
to golan...@googlegroups.com
I'm sorry. I'm gonna go there again.


On Friday, June 29, 2012 6:16:30 AM UTC+1, Karlito wrote:
Palatable Exception Handling V2

ex 1: Let parents handle it
rows = db.RunQuery(query)
print("No exception happened")


ex 2: I'll handle a certain exception
rows, e = db.__RunQuery(query)
handle(e) {
    if e != nil and db.IsDuplicateError(e) {
        print("eh, no big deal")        
        e.handled = True
    }
}
print("No exception other than Duplicate happened")


Has this mail? been separated from another thead? what does that code do? what's handle?

 

ex 3: I'll handle / swallow all exceptions
rows, e = db.__RunQuery(query)
handle(e) {
    if e != nil {
        print("we had an oopsies")        
        e.handled = True
    }
}
print("I'm indefatigable, hahaha!")


Q: What does the leading __ do?
A: It makes any function return the exception instead of raise it.  


you showed two forms of this function call... if this is actually language syntax and it works consistently like map access then fine... but what happens if the function is allowed to return more than one value?
 
Q: What does the handle() { }  do?
A: It makes it hard to accidentally swallow something you didn't mean to.  You have to explicitly say e.handled = True (i.e. hit the snooze button).  Otherwise, a non-nil exception that wasn't handled gets re-raised when the block ends.


ok you explain it here. i still don't get it. to me it looks like a more verbose way of just handling the error in the first place. in fact, i'm sure this same thing can be implemented with an interface to support your .handled whatever, panic(), recover(), defer and a closure.

 
Q: But what's stopping you from not using a handle() block at all, and checking the exception badly by hand?
A: Nothing.  However, static analysis could warn on this (exception object never passed to any handle() block).  Could be a style rule for large projects.


i'm not sure what your idea is here but if you're trying to implement the idea that some? error returned by some function must always at least be checked then it's already trivial in current Go code
 
Q: But nobody needs exceptions!
A: I have no intention of taking my nice python code base and doubling/tripling its size due to menial checks for all database, network, and filesystem calls (which the other devs will assuredly screw up).  You guys are out to lunch.

- Karl


what you don't seem to realise is that python isn't actually any different. in fact it's probably worse because all those things you mention above... when they throw an exception you have to handle it as well. the only difference is that i don't know where the exception came from. if i call into some function that says it throws exception if X fails i can go and handle that. that's ok. and then it calls another function that throws exception Y.




Since all your examples are basically the same. I'd propose you design better apis. if i want an api that has *optional* error handling it's easy to do, in fact i do that in my own db abstraction code in other languages. and the go db abstraction takes a similar approach. in my code i always return a valid object but if the query failed it simply keeps an invalid value for something like fetching the next row. this value will compare to false so the pattern of 100 rows or 0 because there was an error is the same. if you want to know if it actually succeeded or not, then the object has methods to tell you that.


 

Patrick Mylund Nielsen

unread,
Jun 29, 2012, 4:28:36 PM6/29/12
to DisposaBoy, golan...@googlegroups.com
On Fri, Jun 29, 2012 at 10:20 PM, DisposaBoy <dispo...@dby.me> wrote:
Has this mail? been separated from another thead? what does that code do? what's handle?



Ted Stockwell

unread,
Jun 29, 2012, 5:37:18 PM6/29/12
to golang-nuts


On Jun 29, 12:16 am, karl.pick...@gmail.com wrote:
> ex 2: I'll handle a certain exception
> rows, e = db.__RunQuery(query)
> handle(e) {
>     if e != nil and db.IsDuplicateError(e) {
>         print("eh, no big deal")
>         e.handled = True
>     }}
>

I'm definitely not a fan of Go's error handing style but I don't like
this any better because the error handling is still inline with the
code.
One thing that try/catch gives me is proper separation of concerns,
exception handling is separated from application logic.
I would like an error handling style that doesn't force me to pollute
my application code with a boatload of error handling trivia.

Thomas Bushnell, BSG

unread,
Jun 29, 2012, 5:43:33 PM6/29/12
to Ted Stockwell, golang-nuts
On Fri, Jun 29, 2012 at 2:37 PM, Ted Stockwell <emor...@yahoo.com> wrote:
I'm definitely not a fan of Go's error handing style but I don't like
this any better because the error handling is still inline with the
code.
One thing that try/catch gives me is proper separation of concerns,
exception handling is separated from application logic.
I would like an error handling style that doesn't force me to pollute
my application code with a boatload of error handling trivia.

In my experience, the view that these are "separate concerns" is responsible for some of the worst engineering.

When error handling is trivia, it is usually treated as something to be done later, and things which are done later are usually simply not done.

Go encourages you to a style of programming in which you are not constantly ignoring extremely important things under the apprehension that they are "separate concerns" or "trivial".

Thomas 

Patrick Mylund Nielsen

unread,
Jun 29, 2012, 5:54:21 PM6/29/12
to Thomas Bushnell, BSG, Ted Stockwell, golang-nuts
I can count the number of times I've written a Python try/except clause proactively on one hand. I don't think I've ever done foo, _ := bar() in Go outside unit tests.

Ted Stockwell

unread,
Jun 29, 2012, 7:00:03 PM6/29/12
to golang-nuts


On Jun 29, 4:43 pm, "Thomas Bushnell, BSG" <tbushn...@google.com>
wrote:
> In my experience, the view that these are "separate concerns" is
> responsible for some of the worst engineering.
>
> When error handling is trivia, it is usually treated as something to be
> done later, and things which are done later are usually simply not done.
>

Poor logic...
A developer that will not bother using try/catch to handle errors
after a *block* of code is certainly not going to bother with writing
error handling after every frickin line of code.

And...
...try/catch results in code that more readable and maintainable.
...exception handling results in faster running code than error
checking.




Thomas Bushnell, BSG

unread,
Jun 29, 2012, 7:09:35 PM6/29/12
to Ted Stockwell, golang-nuts
On Fri, Jun 29, 2012 at 4:00 PM, Ted Stockwell <emor...@yahoo.com> wrote:
On Jun 29, 4:43 pm, "Thomas Bushnell, BSG" <tbushn...@google.com>
wrote:
> In my experience, the view that these are "separate concerns" is
> responsible for some of the worst engineering.
>
> When error handling is trivia, it is usually treated as something to be
> done later, and things which are done later are usually simply not done.
>

Poor logic...
A developer that will not bother using try/catch to handle errors
after a *block* of code is certainly not going to bother with writing
error handling after every frickin line of code.

Evidence is that this is not so. ::shrug::

And...
...try/catch results in code that more readable and maintainable.
...exception handling results in faster running code than error
checking.

I certainly disagree with the former. The latter is a question of what compilers do and not language features.

Patrick Mylund Nielsen

unread,
Jun 29, 2012, 7:10:52 PM6/29/12
to Ted Stockwell, golang-nuts
Couldn't disagree more. It's not that people are actively trying to ignore errors, it's that they don't know how or where to handle them. There is simply no way to write an idiomatic try/except block for something in a programming language like Python without first experiencing the error, or without looking at the documentation for the package (or its source code if it's poorly documented.) try: except: (all exceptions) is frowned upon.

Go makes this a no-brainer. In the majority of cases, all you need to know is the function's type signature.

Uriel

unread,
Jun 29, 2012, 8:00:31 PM6/29/12
to Patrick Mylund Nielsen, Ted Stockwell, golang-nuts
On Sat, Jun 30, 2012 at 1:10 AM, Patrick Mylund Nielsen
<pat...@patrickmylund.com> wrote:
> Couldn't disagree more. It's not that people are actively trying to ignore
> errors, it's that they don't know how or where to handle them. There is
> simply no way to write an idiomatic try/except block for something in a
> programming language like Python without first experiencing the error, or
> without looking at the documentation for the package (or its source code if
> it's poorly documented.) try: except: (all exceptions) is frowned upon.

In python (and other languages with similar exceptions mechanisms), is
even worse than that, often it is not documented in the API which
exceptions a call might throw.

Java's "checked" exceptions are much maligned, and for good reasons,
but at least they ensure that you know what exceptions to expect.

People like exceptions because the truth is that 99% of the time they
ignore them, and simply pretend they can never happen or that somebody
else up the stack will take care of them.

Python libraries have to document not just all the exceptions they
might throw, but all the exceptions any function they call might
throw.

Nobody documents this properly, much less people using the API handle
all the exceptions properly.


> Go makes this a no-brainer. In the majority of cases, all you need to know
> is the function's type signature.

Go is not perfect, but its error handling is clearly superior to
exceptions in every possible way: explicit, clean, concise, is easy to
follow and to know what might or might not happen.

In languages with exceptions, if you see a function call, you have
really no idea what is going to happen, in Go you know exactly what
can and can not happen.

Uriel

Aram Hăvărneanu

unread,
Jun 29, 2012, 8:03:43 PM6/29/12
to Ted Stockwell, golang-nuts
No.

--
Aram Hăvărneanu

Karlito

unread,
Jun 29, 2012, 9:05:45 PM6/29/12
to golan...@googlegroups.com, Patrick Mylund Nielsen, Ted Stockwell


On Friday, June 29, 2012 7:00:31 PM UTC-5, Uriel DeLarge wrote:
On Sat, Jun 30, 2012 at 1:10 AM, Patrick Mylund Nielsen
<pat...@patrickmylund.com> wrote:
> Couldn't disagree more. It's not that people are actively trying to ignore
> errors, it's that they don't know how or where to handle them. There is
> simply no way to write an idiomatic try/except block for something in a
> programming language like Python without first experiencing the error, or
> without looking at the documentation for the package (or its source code if
> it's poorly documented.) try: except: (all exceptions) is frowned upon.

In python (and other languages with similar exceptions mechanisms), is
even worse than that, often it is not documented in the API which
exceptions a call might throw.

Java's "checked" exceptions are much maligned, and for good reasons,
but at least they ensure that you know what exceptions to expect.

People like exceptions because the truth is that 99% of the time they
ignore them, and simply pretend they can never happen or that somebody
else up the stack will take care of them.

Python libraries have to document not just all the exceptions they
might throw, but all the exceptions any function they call might
throw.

When you have layers of software, I wouldn't assume it's even possible to enumerate all possible errors.  The config file is on NFS, a database is doing something else, an SSL library is used, ...  Embrace the fact that you don't know everything that could happen, but you know what SHOULD normally happen thanks to testing, and if something else happens you damn well want it thrown to what ever module wants to handle it (even if it's simply a log and exit).  

Nobody documents this properly, much less people using the API handle
all the exceptions properly.

People using apis will never handle all errors properly.  (For those of us without google skill programmers)  That's why exceptions are quite useful as a fall back.  


> Go makes this a no-brainer. In the majority of cases, all you need to know
> is the function's type signature.

Go is not perfect, but its error handling is clearly superior to
exceptions in every possible way: explicit, clean, concise, is easy to
follow and to know what might or might not happen.

In languages with exceptions, if you see a function call, you have
really no idea what is going to happen, in Go you know exactly what
can and can not happen.

Except, of course, you don't.  Is someone doing a panic like your json library?  Oh great, now we're back to the worst of both worlds.  You have to write panic safe code except the usage and syntax sucks.  Try again, language designers...

Patrick Mylund Nielsen

unread,
Jun 29, 2012, 9:27:18 PM6/29/12
to Karlito, golan...@googlegroups.com, Ted Stockwell
> When you have layers of software, I wouldn't assume it's even possible to enumerate all possible errors.

> That's why exceptions are quite useful as a fall back.

I don't think you realize it, but you are essentially arguing _for_ Go's approach.

"Panic safe code" isn't a concern at all in Go.

Try again, language designers...
Again, the snide comments aren't helping you at all.

Ted Stockwell

unread,
Jun 29, 2012, 10:45:55 PM6/29/12
to golang-nuts


On Jun 29, 8:27 pm, Patrick Mylund Nielsen <patr...@patrickmylund.com>
wrote:
>
> "Panic safe code" isn't a concern at all in Go.
>


Actually, I can think of at least one situation where I must write
panic safe code.
Suppose I'm writing a server application that accepts requests and
does some very memory intensive things in response.
And suppose there's a definite possibility that a normal request may
cause the application to run out of memory while trying handle a
request (and I believe that currently Go wont use more than 16GB).
In Java, when my app tries to do something that will cause it to run
out of memory the app can just catch OutOfMemoryException and can go
on its merry way (all objects associated with the offending operation
will be garbage collected and I'll get all that memory back).
But in Go the app will instead panic and terminate, this is not a good
trait in a server application, a well built application should be able
to handle this situation gracefully.
So, I will have to handle panics in order to avoid having my app
terminate while performing a normal task.

Ok... but now suppose I actually try to write an app in Go that won't
terminate if it runs out of memory.
You dont know where the application is gonna panic, so, if you are
gonna clean up properly everywhere when such a panic occurs then
you'll have to have panic safe code EVERYWHERE.
Of course, core Go libraries aren't written in this style, so it's not
possible to write applications in Go that can safely recover from a
*normal* out of memory situation.

And, while writing this, I think I just convinced myself that I should
not be using Go...




Patrick Mylund Nielsen

unread,
Jun 29, 2012, 10:55:10 PM6/29/12
to Ted Stockwell, golang-nuts
> Ok... but now suppose I actually try to write an app in Go that won't terminate if it runs out of memory.

You can't do that. (Paraphrasing Ian,) since Go code allocates memory behind the scenes, it's not really possible for Go to continue execution if memory allocation fails.

> You dont know where the application is gonna panic, so, if you are gonna clean up properly everywhere when such a panic occurs then you'll have to have panic safe code EVERYWHERE. Of course, core Go libraries aren't written in this style, so it's not possible to write applications in Go that can safely recover from a *normal* out of memory situation.

I wager that out of memory situations aren't normal.

> And, while writing this, I think I just convinced myself that I should not be using Go...

I'm sorry to hear that. I think these are unfortunate reasons to dismiss the language, and that there are many things to love that are way more prevalent/important that you might have missed.

Henrik Johansson

unread,
Jun 30, 2012, 5:49:22 AM6/30/12
to Ted Stockwell, golang-nuts

You should never catch oom in java. Att that point the behavior of the jvm is undefined. It often allows you too continue but it is just luck. Next oom may very well happen during a jvm specific allocation in which case it dies the hard way.

Java is no different than Go in this regard.

/Henrik

Tim Harig

unread,
Jun 30, 2012, 8:55:12 AM6/30/12
to golang-nuts
On Sat, Jun 30, 2012 at 11:49:22AM +0200, Henrik Johansson wrote:
> You should never catch oom in java. Att that point the behavior of the jvm
> is undefined. It often allows you too continue but it is just luck. Next
> oom may very well happen during a jvm specific allocation in which case it
> dies the hard way.
>
> Java is no different than Go in this regard.

The problem here is that operating systems handle out of memory conditions
differently. Linux, in particular, overcommits memory so that it isn't
possible to send any kind of signal back to a process when it tries to
write past the systems total memory, because it has already promised that
memory to the application. Therefore, when it runs out of memory, the OOM
killer just decides to kill whatever it likes.

This has always been a questionable strategy from the point of stability
but, for desktop and server systems that have considerable swap space, it
is a secondary issue because the system will start thrashing to a halt
before the OOM is actually needed. For embedded systems that are designed
to be more resilient and have less physical memory overall, it becomes a
far more questional strategy.

In any event, since the handling out of memory errors isn't always within
the ability of user programs, so it isn't exactly a language's problem that
there is no graceful way to recover from them. Some languages provide that
ability whether or not it may actually be useful to the system in question.
I might have been useful for go to have better OOM handling for those
systems that do provide it but, the Go developers, having started
developing on Linux in the first place, simply decided to follow that
model.

Ted Stockwell

unread,
Jun 30, 2012, 10:35:48 AM6/30/12
to golang-nuts


On Jun 30, 4:49 am, Henrik Johansson <dahankz...@gmail.com> wrote:
> You should never catch oom in java. Att that point the behavior of the jvm
> is undefined. It often allows you too continue but it is just luck. Next
> oom may very well happen during a jvm specific allocation in which case it
> dies the hard way.
>
> Java is no different than Go in this regard.
>

hmmm, you are correct I suppose.
Though catching oom is something that I have done successfully with
Java (and actually have test cases for).
Perhaps I should start making more use of weak references to avoid
memory issues.




Dave Cheney

unread,
Jun 30, 2012, 6:49:24 PM6/30/12
to Ted Stockwell, golang-nuts
An OOM errr in java is likely to be associatated with the death of one or more threads. As noted in the documentation for thread.Stop, killing a thread will unlock any locks held by that thread, but can leave data structures corrupted if they were being mutated while the lock was held. While you can sometimes continue to operate after your applications exhaust its heap, it is not recommended.

Mike Samuel

unread,
Jul 2, 2012, 1:09:08 PM7/2/12
to golan...@googlegroups.com, Ted Stockwell


On Saturday, June 30, 2012 5:49:22 AM UTC-4, Henrik Johansson wrote:

You should never catch oom in java. Att that point the behavior of the jvm is undefined. It often allows you too continue but it is just luck. Next oom may very well happen during a jvm specific allocation in which case it dies the hard way.

I think "undefined" is a bit strong here.  The threads needed to run any UncaughtThreadHandlers/on-exit-hooks were allocated prior to the OOM so will be entered.  The main source of unbounded behavior happens if those handlers cause allocation, it is neither deterministic nor controllable (Runtime.gc() can be a noop) whether a new GC happens to take advantage of anything that became unreachable as the stack unwound so that may cause another (same since OOM is singleton) OOM.  That OOM is catchable and GC is a source of non-determinism but that is not undefined behavior.

Implementations may die hard but that is a bug.  The language spec specifies that the JVM has to raise an InternalError when any operation (after an OOM or not) would lead to violation of a language level invariant.

Thomas Bushnell, BSG

unread,
Jul 2, 2012, 1:15:41 PM7/2/12
to Mike Samuel, golan...@googlegroups.com, Ted Stockwell
On Mon, Jul 2, 2012 at 10:09 AM, Mike Samuel <mikes...@gmail.com> wrote:
Implementations may die hard but that is a bug.  The language spec specifies that the JVM has to raise an InternalError when any operation (after an OOM or not) would lead to violation of a language level invariant.

I'm afraid I don't buy that reasoning. By that logic, it's a bug in the implementation if the system doesn't raise an exception when an earthquake takes out the data center.

Thomas

Mike Samuel

unread,
Jul 2, 2012, 1:58:44 PM7/2/12
to Thomas Bushnell, BSG, golan...@googlegroups.com, Ted Stockwell
2012/7/2 Thomas Bushnell, BSG <tbus...@google.com>:
No it's not.

The language spec does make guarantees about the state of the machine
when the program halts, but not that a given program will halt or will
report that it cannot make progress towards halting.

When an earthquake takes out a data center, some externality is
preventing your computation from making progress towards halting.

That is different from a program reporting halting (signalling an
error) in a different state than it should report halting (with a
particular exit code as a result of an uncaught exception handler
calling System.exit).

Karlito

unread,
Jul 2, 2012, 2:44:53 PM7/2/12
to golan...@googlegroups.com
You can do:

exc = __run_my_app_code()
and check for strange exceptions there.  You either handle errors right after a function (inline) or in a different function (one of your parents).  Unlike try catch, you can't handle them at some strange forward location in the current function.   So code either goes forward or kicks you back out to your parent.  It can't, however, suddenly jump you forward to a different block at the same indentation level like try/catch does.  I think that could be 33% easier to read than big try/catch blocks :)   Are you saying you prefer try/catch blocks in the same function?


 

Thomas Bushnell, BSG

unread,
Jul 2, 2012, 3:03:21 PM7/2/12
to mikes...@gmail.com, golan...@googlegroups.com, Ted Stockwell
Right, so simply halting computation entirely when OOM happens, without any exception of any kind, would be acceptable according to the standard.

For example, on most Linux systems the oomkiller will just blow the process away when memory can't be provided on demand, since it is normally over-booked.

Ted Stockwell

unread,
Jul 2, 2012, 4:26:28 PM7/2/12
to golang-nuts


On Jul 2, 1:44 pm, Karlito <karl.pick...@gmail.com> wrote:

>
> Unlike try catch, you can't handle them at some strange forward location
> in the current function.
>
It's not some strange forward location, try/catch happens in clearly
defined blocks, like so...

try {
}
catch (...) {
}

Calling catch 'some strange forward location' is like saying that an
if statement handles the else case in 'some strange forward
location'...

if (...) {
}
else {
}

...notice the similarity?




>
> Are you
> saying you prefer try/catch blocks in the same function?
>

Yes, that's what I'm sayin.

Ted Stockwell

unread,
Jul 2, 2012, 4:35:00 PM7/2/12
to golang-nuts


On Jul 2, 2:03 pm, "Thomas Bushnell, BSG" <tbushn...@google.com>
wrote:
> Right, so simply halting computation entirely when OOM happens, without any
> exception of any kind, would be acceptable according to the standard.
>

Wait, what?
I can't see how you can conclude this from anything that Mike Samuel
just said.

Mike Samuel

unread,
Jul 2, 2012, 4:37:02 PM7/2/12
to Thomas Bushnell, BSG, golan...@googlegroups.com, Ted Stockwell
2012/7/2 Thomas Bushnell, BSG <tbus...@google.com>:
> Right, so simply halting computation entirely when OOM happens, without any
> exception of any kind, would be acceptable according to the standard.


No. A JVM cannot simply halt. A conforming JVM could refuse to halt,
ever, as soon as an OOM happens, but it cannot report completion to
its parent without completing the steps required before reporting
completion.


I'm sure you're familiar with these terms, but let me define them to be clear:

TCB (Trusted Computing Base) - The OS kernel assumes the hardware
works almost as advertised so the hardware is in the kernel's TCB.
User mode processes assume the OS works almost as advertise so the OS
is in user mode processes' TCB. The JVM similarly has a TCB.
Computers

Specification of X - Bounds on what X does when X's TCB behaves as expected.

Externality - Unexpected behavior in the TCB.


If a TCB violation occurs, then the specification places no bounds on behavior.
If the data-center is nuked, no parent thread of a properly
functioning operating-system/user-space stack could observe a
non-conforming report of completion.

If no TCB violation occurs, and the JVM just halts when the
specification says otherwise, then a properly function OS/user-space
stack could observe a non-conforming report of completion.

Paul Borman

unread,
Jul 2, 2012, 4:38:12 PM7/2/12
to mikes...@gmail.com, Thomas Bushnell, BSG, golan...@googlegroups.com, Ted Stockwell
So no kill -9?

Paul Borman

unread,
Jul 2, 2012, 4:39:36 PM7/2/12
to Ted Stockwell, golang-nuts
Clearly some people like exceptions and try/catch blocks.  Other people do not.  No use trying to convince one side of the other's view point.

Go is a language designed to not have exceptions.  There are many programming languages to choose from.  If you want exceptions then Go is not the programming language for you.  Within your own code, if you want, you can use panic/recover, but you should never expect other code to recover your panic.

    -Paul

Thomas Bushnell, BSG

unread,
Jul 2, 2012, 4:55:20 PM7/2/12
to mikes...@gmail.com, golan...@googlegroups.com, Ted Stockwell
The advertised functioning of the OS in the case of Linux is to sometimes terminate processes in memory crunches without notification. So, I still can't tell what you're telling me about Java: a Java program can rely on always getting an exception before it's terminated for out-of-memory reasons, or not. If so, then the standard cannot be properly implemented on Linux. If not, then we're back where we started: a Java program is sometimes notified about out-of-memory conditions, and sometimes not, all on compliant implementations.


On Mon, Jul 2, 2012 at 1:37 PM, Mike Samuel <mikes...@gmail.com> wrote:

Mike Samuel

unread,
Jul 2, 2012, 5:18:28 PM7/2/12
to Thomas Bushnell, BSG, golan...@googlegroups.com, Ted Stockwell
2012/7/2 Thomas Bushnell, BSG <tbus...@google.com>:
> The advertised functioning of the OS in the case of Linux is to sometimes
> terminate processes in memory crunches without notification. So, I still
> can't tell what you're telling me about Java: a Java program can rely on
> always getting an exception before it's terminated for out-of-memory
> reasons, or not. If so, then the standard cannot be properly implemented on
> Linux.

Sure. OS signals are externalities since the language specification
assumes optimistically that they don't exist. Each JVM makes
additional assumptions about its stack and most do try to handle
signals other than SIGKILL elegantly by weakening the assumptions made
by the language spec. sun.misc.SignalHandler is widely implemented by
JVMs, but since they are extensions to the language they come with
warnings like

"""
The Class sun.misc.SignalHandler is a sun internal class and may be
removed/changed in future java releases.
The packages sun and sunw contains mostly undocumented internal
classes from sun and if they are used you will get compiler warnings
like this:
warning: sun.misc.SignalHandler is Sun proprietary API and may be
removed in a future release.
"""


> If not, then we're back where we started: a Java program is sometimes
> notified about out-of-memory conditions, and sometimes not, all on compliant
> implementations.

Java's OutOfMemoryError is only for the failure of the JVM to satisfy
the "new" bytecode instruction as required by a particular JVM
light-weight thread.

It should not be raised in any thread when some other process requests
memory and fails to get it or when an administrator or babysitter
daemon decides that the machine over-committed and culls some
processes.

Karlito

unread,
Jul 2, 2012, 5:39:27 PM7/2/12
to golan...@googlegroups.com, Ted Stockwell

On Monday, July 2, 2012 3:39:36 PM UTC-5, Paul Borman wrote:
Clearly some people like exceptions and try/catch blocks.  Other people do not.  No use trying to convince one side of the other's view point.

Go is a language designed to not have exceptions.  There are many programming languages to choose from.  If you want exceptions then Go is not the programming language for you.  Within your own code, if you want, you can use panic/recover, but you should never expect other code to recover your panic.

    -Paul


I don't think it's a person specific issue.  I can't stand using exceptions in any of my c++ projects, so I never do.  In python though, I can use either method of signaling errors.  Sometimes exceptions, sometimes return codes.   Either way in python is fairly easy.   It depends on the project and even the module in the project.  Error handling is never one size fits all.

Think of /bin/sh.  You can use set -e to trap all errors, or you can choose to check every thing by hand.  I have used both techniques there too.  It's a shame GO can't be as friendly as 30 year old sh :)

Thomas Bushnell, BSG

unread,
Jul 2, 2012, 5:41:29 PM7/2/12
to mikes...@gmail.com, golan...@googlegroups.com, Ted Stockwell
On Mon, Jul 2, 2012 at 2:18 PM, Mike Samuel <mikes...@gmail.com> wrote:
> If not, then we're back where we started: a Java program is sometimes
> notified about out-of-memory conditions, and sometimes not, all on compliant
> implementations.

Java's OutOfMemoryError is only for the failure of the JVM to satisfy
the "new" bytecode instruction as required by a particular JVM
light-weight thread.

Sure, but I want to stress that there are cases where it will be unable to satisfy that instruction and the result is that the program is simply immediately terminated.

Thomas

Mike Samuel

unread,
Jul 2, 2012, 6:29:15 PM7/2/12
to Thomas Bushnell, BSG, golan...@googlegroups.com, Ted Stockwell
2012/7/2 Thomas Bushnell, BSG <tbus...@google.com>:
Can you give an example where the spec's TCB assumptions hold?

Thomas Bushnell, BSG

unread,
Jul 2, 2012, 6:36:49 PM7/2/12
to mikes...@gmail.com, golan...@googlegroups.com, Ted Stockwell
On Mon, Jul 2, 2012 at 3:29 PM, Mike Samuel <mikes...@gmail.com> wrote:
> Sure, but I want to stress that there are cases where it will be unable to
> satisfy that instruction and the result is that the program is simply
> immediately terminated.

Can you give an example where the spec's TCB assumptions hold?

You said that the assumption is that the OS works as advertised. The advertised behavior of Linux is that when the kernel cannot deal with a memory crunch, it will terminate processes immediately.

If the "new" bytecode instruction results in a call to sbrk the use of the new memory, which cannot be satisfied because of a memory crunch, the kernel's oom killer may immediately select the current process as the one to kill, directly in response to its own consumption.

Thomas


Paul Borman

unread,
Jul 2, 2012, 6:49:45 PM7/2/12
to Thomas Bushnell, BSG, mikes...@gmail.com, golan...@googlegroups.com, Ted Stockwell
So sbrk is one way to increase your address space.  Another way is to mmap anonymous memory.  Go does the latter.  I believe it is true for both cases (certainly the mmap case) that Linux gives you the address space but doesn't promise you have memory to fulfill the request.  When you page fault in a previous unreferenced page, and Linux has no free pages to give you, it will kill you.  There is no return value to say it didn't work as the allocation was the side affect of simply referring to a virtual address in a previously unreferenced page.  Linux is pretty loosey goosey about memory.

Then there are the OOM killers that go out and proactively search for victims.

In any event, there is no possible way on a UNIX or UNIX like system for a program to trap all the possible ways to die.  Kill -9 always wins and the kernel can do what ever it wants.

    -Paul

Benny Siegert

unread,
Jul 3, 2012, 8:12:29 AM7/3/12
to golang-nuts
On Mon, Jul 2, 2012 at 11:18 PM, Mike Samuel <mikes...@gmail.com> wrote:
> Sure. OS signals are externalities since the language specification
> assumes optimistically that they don't exist. Each JVM makes
> additional assumptions about its stack and most do try to handle
> signals other than SIGKILL elegantly by weakening the assumptions made
> by the language spec. sun.misc.SignalHandler is widely implemented by
[...]

Why is this thread suddenly about Java?

--Benny.

kortschak

unread,
Jul 3, 2012, 8:21:29 AM7/3/12
to golan...@googlegroups.com
A ThreadException was thrown and not properly handled.

Dmitry Maluka

unread,
Jul 3, 2012, 8:45:01 AM7/3/12
to golan...@googlegroups.com
On 07/03/2012 12:39 AM, Karlito wrote:
> Think of /bin/sh. You can use set -e to trap all errors, or you can
> choose to check every thing by hand. I have used both techniques
> there too. It's a shame GO can't be as friendly as 30 year old sh :)

Shell is not a general-purpose language. It is a specialized tool for
running programs. What is good for a particular specialized tool is not
necessarily good for a general-purpose programming language.

Ted Stockwell

unread,
Jul 3, 2012, 10:26:14 AM7/3/12
to golang-nuts


On Jul 3, 7:21 am, kortschak <dan.kortsc...@adelaide.edu.au> wrote:
> A ThreadException was thrown and not properly handled.
>
>
(Score:5, Funny)
Google Groups need to add mod points :-)

Paul Borman

unread,
Jul 3, 2012, 11:00:10 AM7/3/12
to golan...@googlegroups.com
If you want exceptions (actually, try/catch/finally) in Go, please read the Go faq.

Why does Go not have exceptions?

We believe that coupling exceptions to a control structure, as in the try-catch-finally idiom, results in convoluted code. It also tends to encourage programmers to label too many ordinary errors, such as failing to open a file, as exceptional.

Go takes a different approach. For plain error handling, Go's multi-value returns make it easy to report an error without overloading the return value. A canonical error type, coupled with Go's other features, makes error handling pleasant but quite different from that in other languages.

Go also has a couple of built-in functions to signal and recover from truly exceptional conditions. The recovery mechanism is executed only as part of a function's state being torn down after an error, which is sufficient to handle catastrophe but requires no extra control structures and, when used well, can result in clean error-handling code.

See the Defer, Panic, and Recover article for details.

You may strongly disagree with the Go authors.  I strongly agree with them.  If you are uncomfortable writing code without try/catch/finally then Go is not the language for you.  There is no point in arguing for something the Go authors have pretty clearly stated they are opposed to.  You are free to use a different language or create your own.

You shell example was a very poor and incorrect analogy.  In Go you can write a handler that handles all signals or write handlers for individual signals.  So yes, Go can do what shell did.

To be clear, Go does have exceptions.  They are done with panic/defer/recover and are not meant to be used to return mundane errors.

Karlito

unread,
Jul 3, 2012, 11:15:07 AM7/3/12
to golan...@googlegroups.com

On Tuesday, July 3, 2012 10:00:10 AM UTC-5, Paul Borman wrote:
If you want exceptions (actually, try/catch/finally) in Go, please read the Go faq.

Why does Go not have exceptions?

We believe that coupling exceptions to a control structure, as in the try-catch-finally idiom, results in convoluted code. It also tends to encourage programmers to label too many ordinary errors, such as failing to open a file, as exceptional.

Go takes a different approach. For plain error handling, Go's multi-value returns make it easy to report an error without overloading the return value. A canonical error type, coupled with Go's other features, makes error handling pleasant but quite different from that in other languages.

Go also has a couple of built-in functions to signal and recover from truly exceptional conditions. The recovery mechanism is executed only as part of a function's state being torn down after an error, which is sufficient to handle catastrophe but requires no extra control structures and, when used well, can result in clean error-handling code.

See the Defer, Panic, and Recover article for details.

You may strongly disagree with the Go authors.  I strongly agree with them.  If you are uncomfortable writing code without try/catch/finally then Go is not the language for you.  There is no point in arguing for something the Go authors have pretty clearly stated they are opposed to.  You are free to use a different language or create your own.

I'm sorry, you must not have actually read my proposal because it doesn't use anything like try/catch/finally.  

What I have also read on the GO site is incredibly buggy code like:
* Most people using fmt.Println are buggy and don't check errors
* Everyone doing defer file.Close() is buggy since that doesn't check errors

Paul Borman

unread,
Jul 3, 2012, 11:45:20 AM7/3/12
to Karlito, golan...@googlegroups.com
On Tue, Jul 3, 2012 at 8:15 AM, Karlito <karl.p...@gmail.com> wrote:
I'm sorry, you must not have actually read my proposal because it doesn't use anything like try/catch/finally.  

try/catch/finally have been argued for in this thread.

Your proposal is sort of muddled in between.  "try" is calling the function and "catch" is calling handle().  As far as I can see, "finally" is missing.  It leads to the python style of "call a bunch of functions and then check to see if any threw an exception/error." 

Jonathan Amsterdam

unread,
Jul 5, 2012, 11:46:36 AM7/5/12
to golan...@googlegroups.com, Ted Stockwell
 In python though, I can use either method of signaling errors.  Sometimes exceptions, sometimes return codes.   Either way in python is fairly easy.   It depends on the project and even the module in the project.  Error handling is never one size fits all.

In Go though, I can use either method of signaling errors.  Sometimes panic(), sometimes return codes.   Either way in Go is fairly easy. 

Karlito

unread,
Jul 6, 2012, 10:27:07 AM7/6/12
to golan...@googlegroups.com


On Tuesday, July 3, 2012 10:15:07 AM UTC-5, Karlito wrote:

On Tuesday, July 3, 2012 10:00:10 AM UTC-5, Paul Borman wrote:
If you want exceptions (actually, try/catch/finally) in Go, please read the Go faq.

Why does Go not have exceptions?

We believe that coupling exceptions to a control structure, as in the try-catch-finally idiom, results in convoluted code. It also tends to encourage programmers to label too many ordinary errors, such as failing to open a file, as exceptional.

Go takes a different approach. For plain error handling, Go's multi-value returns make it easy to report an error without overloading the return value. A canonical error type, coupled with Go's other features, makes error handling pleasant but quite different from that in other languages.

Go also has a couple of built-in functions to signal and recover from truly exceptional conditions. The recovery mechanism is executed only as part of a function's state being torn down after an error, which is sufficient to handle catastrophe but requires no extra control structures and, when used well, can result in clean error-handling code.

See the Defer, Panic, and Recover article for details.

You may strongly disagree with the Go authors.  I strongly agree with them.  If you are uncomfortable writing code without try/catch/finally then Go is not the language for you.  There is no point in arguing for something the Go authors have pretty clearly stated they are opposed to.  You are free to use a different language or create your own.

I'm sorry, you must not have actually read my proposal because it doesn't use anything like try/catch/finally.  

What I have also read on the GO site is incredibly buggy code like:
* Most people using fmt.Println are buggy and don't check errors
* Everyone doing defer file.Close() is buggy since that doesn't check errors

Is nobody going to step up to bat and defend defer file.Close() as NOT being buggy?   Writing a file over NFS with quotas on can make close(2) fail, in the real world.    So can closing it twice.  Now grep the GO library source code for defer and be afraid.   If I wanted a language that hid bugs, I'd use perl.

Peter Bourgon

unread,
Jul 6, 2012, 10:38:59 AM7/6/12
to Karlito, golan...@googlegroups.com
> Is nobody going to step up to bat and defend defer file.Close() as NOT being
> buggy? Writing a file over NFS with quotas on can make close(2) fail, in
> the real world. So can closing it twice. Now grep the GO library source
> code for defer and be afraid. If I wanted a language that hid bugs, I'd
> use perl.

1. If file.Close() returns a non-nil error, what is the appropriate
action to take? Can such errors be resolved by the program?

2. Engaging a community with hostility, as you are doing here, is
generally not conducive to a productive dialog.

Robert Johnstone

unread,
Jul 6, 2012, 12:38:06 PM7/6/12
to golan...@googlegroups.com, Patrick Mylund Nielsen, Ted Stockwell
You forgot verbose.  So, Go's approach is inferior in at least one aspect.

I'm not arguing against Go's preferred method of handling errors.  I rarely use panics in my Go code.  But telling people that everything is perfect when they will be literally staring at extra lines of code is not going to succeed.   I don't believe that ignoring the limitations of an approach is more persuasive that an open discussion of the trade-offs involved.


On Friday, 29 June 2012 20:00:31 UTC-4, Uriel DeLarge wrote:
Go is not perfect, but its error handling is clearly superior to
exceptions in every possible way: explicit, clean, concise, is easy to
follow and to know what might or might not happen.

Andrew Gerrand

unread,
Jul 6, 2012, 5:27:58 PM7/6/12
to Robert Johnstone, golan...@googlegroups.com, Patrick Mylund Nielsen, Ted Stockwell
On 6 July 2012 09:38, Robert Johnstone <r.w.jo...@gmail.com> wrote:
> You forgot verbose. So, Go's approach is inferior in at least one aspect.
>
> I'm not arguing against Go's preferred method of handling errors. I rarely
> use panics in my Go code. But telling people that everything is perfect
> when they will be literally staring at extra lines of code is not going to
> succeed. I don't believe that ignoring the limitations of an approach is
> more persuasive that an open discussion of the trade-offs involved.

It's all about perspective:

You have to look at all that error handling code! I hate it!

vs

You can see all the error handling code! I love it!

Andrew

Thomas Bushnell, BSG

unread,
Jul 6, 2012, 6:50:50 PM7/6/12
to Robert Johnstone, golan...@googlegroups.com, Patrick Mylund Nielsen, Ted Stockwell
The mention of whether Go is to verbose in handling errors (I think not) or that there is a problem with the defer close pattern, leads me to wonder further about that pattern and whether Go is really as needlessly verbose as is claimed.

Consider a function which is like this

func doSomething(name string, arg int) (err error) {
  f := openSomething(name)
  defer f.Close()

  f.FirstOperation(arg)
  f.SecondOperation()
  return nil
}

Now the proponents of exceptions want us to think that this already handles errors, while the Go code must add error handling logic to deal with error returns from the various cases. We end up with this in Go:

func doSomething(name string) (err error) {
  var f Something
  if f, err = openSomething(name); err != nil {
    return
  }
  defer f.Close()

  if err = f.FirstOperation(arg); err != nil {
    return
  }
  err = f.SecondOperation()
  return
}

It looks as if in Go the addition of error handling has expanded the code, while the original (supposedly) is all fine if we had exceptions.

But what if f.Close returns an error, as was suggested by the correspondent worried about NFS? I'm more interested in the case where f.Close is some kind of good-to-do cleanup operation, but we don't want to reflect an error to the caller if it fails. Now add some adequate logging to this function:

func doSomething(name string, arg int) (err error) {
  var f Something
  f, err = openSomething(name); err != nil {
    logErrorf("open %s failed: %v", name, err)
    return
  }
  defer func() {
    errx := f.Close()
    logWarningf("close %s failed: %v", name, err)
    return
  }

  if err = f.FirstOperation(arg); err != nil {
    logErrorf("first operation %s (%d) failed: %v", name, arg, err)
    return
  }
  if err = f.SecondOperation(); err != nil {
    logErrorf("second operation %s failed: %v", name, err)
  }
  return
}

What would this look like for exceptions? We start with this, which I agree looks cleaner than the first Go version with errors:

def doSomething(name, arg):
  f = openSomething(name)
  try:
    f.firstOperation(arg)
    f.secondOperation()
  except:
    f.close()
    raise
  f.close

Now it's a bit stuttery (the close was repeated) but it looks tighter than the Go code. I assume this is the sort of thing exception proponents care about. But what if we want to add the adequate logging above to this:

def doSomething(name arg):
  try:
    f.openSomething(name)
  except e:
    logError("open ", name, " failed: ", e
    raise

  try:
    try:
      f.firstOperation(arg)
    except e:
      logError("first operation ", name, "( ", arg, ") failed: ", e)
      raise
    try:
      f.secondOperation()
    except e:
      logError("second operation ", name, "failed: ", e)
      raise
  except e:
    try:
      f.close()
    except ex:
      logWarning("close ", name, "failed: ", ex)
      # don't re-raise ex
    raise

  try:
    f.close()
  except ex:
    logWarning("close ", name, "failed: ", ex)
    # don't re-raise ex

As soon as you try to actually do something with errors, and as soon as you actually care where the error comes from (which happens if you wish to do something as simple as log it clearly with semantic information that may not be visible in a stack trace), the version with exceptions becomes a tangle of un-navigable spaghetti.

Thomas

Jonathan Amsterdam

unread,
Jul 6, 2012, 11:57:28 PM7/6/12
to golan...@googlegroups.com

Is nobody going to step up to bat and defend defer file.Close() as NOT being buggy?   Writing a file over NFS with quotas on can make close(2) fail, in the real world.    So can closing it twice.  Now grep the GO library source code for defer and be afraid.   If I wanted a language that hid bugs, I'd use perl.

You can't tell much just from a grep. defer file.Close() is not buggy if you're reading the file (as the error is irrelevant). It is a bug if you're writing a file. Arguably the one in image/png/writer.go is buggy. 
 

Russel Winder

unread,
Jul 7, 2012, 1:13:50 AM7/7/12
to Thomas Bushnell, BSG, golan...@googlegroups.com
Thomas,

On Fri, 2012-07-06 at 15:50 -0700, Thomas Bushnell, BSG wrote:
[…]
> What would this look like for exceptions? We start with this, which I agree
> looks cleaner than the first Go version with errors:

Assuming this is intended to be Python, your start point is wrong. This
is not to say you cannot remake your case, just that you need to compare
modern Python against modern Go.

> def doSomething(name, arg):
> f = openSomething(name)
> try:
> f.firstOperation(arg)
> f.secondOperation()
> except:
> f.close()
> raise
> f.close

should read:

def doSomething(name, arg):
with openSomething(name) as f:
f.firstOperation(arg)
f.secondOperation()

Context managers in Python for versions > 2.5 provide the
__entry__/__exit__ hooks needed to realize all the RAII-style
protections. In Python 3 and later all I/O activity (including
networking) works with context managers. To handle all the logging
activity from your later examples, you would define a context manager to
deal with the boilerplate you put forward trying to show Python is at
least as bad as Go on this issue.

To be honest all this "exceptions vs. error codes, one is right this
other is evil" is counterproductive and wasting of time and energy. The
Go team have made the decision to do everything with error codes, Python
does everything with exceptions. That is the nature of the languages,
and they develop in tune with the philosophical approach. Moreover
programmer usage should be in harmony with the philosophy to create
idiomatic readable code. Sometimes there will be cross-fertilization:
RAII from C++ was taken into Python as context managers because, in the
presence of exceptions, it is a damn fine idea. Java came late to this
party but now has ARM (automated resource management, aka "try with
resources"). It isn't clear that any of this applies to Go since there
are no exceptions – panic doesn't really count.

--
Russel.
=============================================================================
Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel...@ekiga.net
41 Buckmaster Road m: +44 7770 465 077 xmpp: rus...@winder.org.uk
London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
signature.asc

roger peppe

unread,
Jul 7, 2012, 8:24:23 AM7/7/12
to Karlito, golan...@googlegroups.com


On Jul 6, 2012 3:27 PM, "Karlito" <karl.p...@gmail.com> wrote:
>
>
>
> On Tuesday, July 3, 2012 10:15:07 AM UTC-5, Karlito wrote:
>>
>>
>> On Tuesday, July 3, 2012 10:00:10 AM UTC-5, Paul Borman wrote:
>>>
>>> If you want exceptions (actually, try/catch/finally) in Go, please read the Go faq.
>>> Why does Go not have exceptions?
>>>
>>> We believe that coupling exceptions to a control structure, as in the try-catch-finally idiom, results in convoluted code. It also tends to encourage programmers to label too many ordinary errors, such as failing to open a file, as exceptional.
>>>
>>> Go takes a different approach. For plain error handling, Go's multi-value returns make it easy to report an error without overloading the return value. A canonical error type, coupled with Go's other features, makes error handling pleasant but quite different from that in other languages.
>>>
>>> Go also has a couple of built-in functions to signal and recover from truly exceptional conditions. The recovery mechanism is executed only as part of a function's state being torn down after an error, which is sufficient to handle catastrophe but requires no extra control structures and, when used well, can result in clean error-handling code.
>>>
>>> See the Defer, Panic, and Recover article for details.
>>>
>>> You may strongly disagree with the Go authors.  I strongly agree with them.  If you are uncomfortable writing code without try/catch/finally then Go is not the language for you.  There is no point in arguing for something the Go authors have pretty clearly stated they are opposed to.  You are free to use a different language or create your own.
>>
>>
>> I'm sorry, you must not have actually read my proposal because it doesn't use anything like try/catch/finally.  
>>
>> What I have also read on the GO site is incredibly buggy code like:
>> * Most people using fmt.Println are buggy and don't check errors
>> * Everyone doing defer file.Close() is buggy since that doesn't check errors
>
>
> Is nobody going to step up to bat and defend defer file.Close() as NOT being buggy?   Writing a file over NFS with quotas on can make close(2) fail, in the real world.    So can closing it twice.  Now grep the GO library source code for defer and be afraid.   If I wanted a language that hid bugs, I'd use perl.

When I particularly care about checking the error returned by Close, I sometimes write a function like this:

func checkClose(c io.Closer, err *error) {
    cerr := c.Close()
    if *err == nil {
        *err = cerr
    }
}

Then I can write

  defer checkClose(f, &err)

and not worry that the close error might be ignored.

Ted Stockwell

unread,
Jul 8, 2012, 1:31:58 PM7/8/12
to golang-nuts


On Jul 6, 5:50 pm, "Thomas Bushnell, BSG" <tbushn...@google.com>
wrote:
>
> As soon as you try to actually *do *something with errors, and as soon as
> you actually *care *where the error comes from (which happens if you wish
> to do something as simple as log it clearly with semantic information that
> may not be visible in a stack trace), the version with exceptions becomes a
> tangle of un-navigable spaghetti.
>

A rule of good design is to design for the most common usage, while
making it possible to support atypical usage.
This a good rule whether designing a GUI, an API, or a language.
You admitted that the most common usage was less verbose when using
exceptions, and then you went ahead and justified Go's approach using
a very atypical example.
You just turned good design on its head.

Thomas Bushnell, BSG

unread,
Jul 8, 2012, 1:37:29 PM7/8/12
to Ted Stockwell, golang-nuts
On Sun, Jul 8, 2012 at 10:31 AM, Ted Stockwell <emor...@yahoo.com> wrote:
A rule of good design is to design for the most common usage, while
making it possible to support atypical usage.
This a good rule whether designing a GUI, an API, or a language.
You admitted that the most common usage was less verbose when using
exceptions, and then you went ahead and justified Go's approach using
a very atypical example.
You just turned good design on its head.

You really think that correct error handling and logging is "very atypical"?  That's a sad indictment of programmers, not a criticism of my post.

Florian Weimer

unread,
Jul 8, 2012, 1:51:32 PM7/8/12
to golan...@googlegroups.com
* Thomas Bushnell:

> You really think that correct error handling and logging is "very
> atypical"?

In many cases, crash dumps or backtraces are sufficient because the
program can be aborted safely. If your program isn't in this
category, you cannot use Go anyway because Go handles memory
allocation errors this way.

Thomas Bushnell, BSG

unread,
Jul 8, 2012, 2:00:30 PM7/8/12
to Ted Stockwell, golang-nuts
On Sun, Jul 8, 2012 at 10:31 AM, Ted Stockwell <emor...@yahoo.com> wrote:

A rule of good design is to design for the most common usage, while
making it possible to support atypical usage.
This a good rule whether designing a GUI, an API, or a language.
You admitted that the most common usage was less verbose when using
exceptions, and then you went ahead and justified Go's approach using
a very atypical example.
You just turned good design on its head.


I most certainly did not "admit that the most common usage was less verbose." I claimed that in toy examples, or code with inadequate logging or error-checking, exceptions produce less verbose code, but that in real, worthy code, which I take to mean "handles errors correctly and robustly, and has adequate logging", exceptions cause a significant problem.  A great example is this, from the Python tutorial at http://docs.python.org/tutorial/errors.html:

import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError as e:
    print "I/O error({0}): {1}".format(e.errno, e.strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise

This code is seriously problematic. It exemplifies a common style: instead of checking for exceptions around each call, we do one big omnibus try construct around many calls, and then string the errors together.

It is difficult to understand: to make sense of it, we need to know that "open" and "readline" can raise IOError, and "int" can raise ValueError. (I'll pass over with minimal comment the bizarre way in which this example is getting the exception type from a global variable.) And we don't have much documentation of which exceptions these functions can return, so we're just hoping that there isn't a way readline or open can return ValueError. (In a real case, "myfile.txt" is probably a variable, which, due to a bug, could be non-string. Wouldn't that cause open to return a ValueError?)

Thomas

Thomas Bushnell, BSG

unread,
Jul 8, 2012, 2:02:51 PM7/8/12
to Florian Weimer, golan...@googlegroups.com
I don't know what to say to this, except that I very strongly disagree, and I'm glad Go makes a more robust style of programming simple.

Dmitry Maluka

unread,
Jul 8, 2012, 3:10:22 PM7/8/12
to golan...@googlegroups.com
On 07/08/2012 08:51 PM, Florian Weimer wrote:
> In many cases, crash dumps or backtraces are sufficient because the
> program can be aborted safely. If your program isn't in this
> category, you cannot use Go anyway because Go handles memory
> allocation errors this way.

It's all-or-nothing thinking. Memory is a very special kind of the
resource. Go runtime vitally needs it. As for resources like files or
connections, the runtime knows nothing about them. Who if not the
programmer should take care of failure modes associated with them?
Reply all
Reply to author
Forward
0 new messages