News for hackers. Stuff that matters.
Re:Why I’m not leaving Python for Go by crazygringo on Sunday September 23, 2012 @07:53PM (#4562577)
If you use a language that uses error codes, then you're forced to explicitly think about what to do in every single error case (or not, and accept the consequences). This can add a lot of mental overhead, but can result in a much more robust and well-thought-out program. But because more logic is involved period (to handle the robustness), the program is necessarily more complex.

If you use exception handling, then suddenly catching errors becomes much easier, and writing code is faster, but it's not like your program is any more robust. If you catch an error up at the top, your program or function is probably just going to quit. Of course, you can add more code to deal individually with each of the exceptions in more robust ways, even to the point of wrapping each statement in its own try/catch block, but then it's no different in practice from returning error codes.

In the end, I just don't see much of a practical difference. In both cases, if you want to be a lazy or rapid programmer, errors will lead to your software just not working. And if you want to be conscientious about your errors, then you can do that in both cases.

Exception handling lets you handle errors "at a distance". It's convenient, but harder to keep track of. Returning errors keeps your code execution where you can see it, and you always know where it is. It's simpler, but more verbose.

Re:Why I’m not leaving Python for Go by Sidnicious on Sunday September 23, 2012 @08:20PM (#4562644)
The default behavior for an error in a programing language with exceptions is to crash. This gets your program back to a known state (i.e. not running). It's impossible for code to blindly continue when something bad happens.

If you want to handle some error in a way other than crashing, handle it. Web frameworks usually catch exceptions that arise while a request is being handled, finish the request, and keep handling new requests. You handle things more specifically only as needed.

I like that behavior so much more than having a program keep running in an unknown state unless you handle errors line by line (and value it more than keeping code execution where I can see it). I don't think my programming language knows what errors are very important, either — that depends way too much on context.

Re:Why I’m not leaving Python for Go by stcredzero on Monday September 24, 2012 @03:38AM (#4563615)
> The default behavior for an error in a programing language with exceptions is to crash. This gets your program back to a known state (i.e. not running). It's impossible for code to blindly continue when something bad happens.

In Smalltalk, the default behavior for an error is pretty much business as usual, because exception handling is mostly just Smalltalk code running normally. In some Smalltalks, you can override the "top level handler" and ensure that an app never crashes. (An infinitely growing collection will exhaust heap and crash the program that way.)

Re:Why I’m not leaving Python for Go by dmpk2k on Sunday September 23, 2012 @10:09PM (#4562895)
I don't know about Go, but lint is commonly used to enforce checking of return values in C. Presumably Go could bake an option into the compiler to enforce this too.
Re:Why I’m not leaving Python for Go by luriel on Sunday September 23, 2012 @10:45PM (#4562974)
In Go unused variables are an error, so you are forced to either handle errors or explicitly ignore them (by assigning them to _).
Re:Why I’m not leaving Python for Go by Djehngo on Monday September 24, 2012 @06:38AM (#4563991)
Sort of, you can actually get away with invoking a function and not assigning its result at all

I think assigning the error to _ is only necassary when you have multiple return values(one of which is the error) and you are interested in at least one of them.

e.g.

    returnsTwoValues()
is legal

    x := returnsTwoValues()
is not

maps are also interesting because

    value := someMap[key]
is valid and

    value, keyIsPresent := someMap[key]
is also valid.
Re:Why I’m not leaving Python for Go by wpietri on Monday September 24, 2012 @12:46AM (#4563255)
The difference for me is whether I'm trying to reduce MTBF (mean time between failures) or MTTR (mean time to recovery).

I'm in the first mode when I'm writing high-quality code to solve stable, well-understood problems.

I'm in the latter when I'm doing almost anything else. E.g., prototyping, exploring, pushing out a MVP for user testing, adding a quick-and-dirty version of a feature to get real-world feedback.

In the latter mode, I'm very tolerant of errors just as long as I can diagnose the problem quickly. The way I start is to catch exceptions at a very high level, tell the user something nice, and have myself paged. If something blows up, I fix it quickly. There's no sense in making code robust if I don't know if it will exist next week.

Basically, the two approaches are the same only if you have infinite time and money. Google does, so I guess Go makes sense for them. But if this fellow's take is correct, Go's much less interesting to me as a general-purpose language.

Re:Why I’m not leaving Python for Go by hntester123 on Monday September 24, 2012 @11:52AM (#4565225)
That's an interesting idea: to only catch exceptions at a very high level (for fast prototyping). I tried it out with this test program:

http://pastie.org/4791686

Though it works, one potential issue I found with it is that it does not give enough context as to where in the program the exception occurred. E.g. if I have more than one open() call (all for read mode) in the code, it will give the same error message for an exception occurring on any of those open() calls (as long as the exceptions all happen for the same underlying reason, such as "file not found". E.g.:

Exception occurred: IOError(2, 'No such file or directory')

Had you come across this and found any way to handle it? I though of passing some unique code for each case, but there seems to be no way to do it, because we are not calling the except clause ourselves - Python does it.

Edit: just thought of a (crude) way to handle that issue: declare a global variable, say, "location", and set it to a different numeric or string value at each place in the code where an exception may be thrown, or at least at one place, say the top of the function, in each function or method. And then in the single except clause, print the value:

print "location=", location

This will at least help narrow down the area of code in which the exception was thrown.

Re:Why I’m not leaving Python for Go by dkersten on Monday September 24, 2012 @02:03PM (#4566036)
Huh? Most languages with exceptions provide stack traces, so you can find which function (and line) caused the exception and also what functions were called up to the function that caused the exception. This makes it pretty easy to find out which call to open() caused the exception.
Re:Why I’m not leaving Python for Go by hntester123 on Monday September 24, 2012 @02:40PM (#4566214)
Heck, I commented in a hurry without thinking :( I did know about stack traces (used so many times), and you're right, of course. Thanks for pointing it out, though :). Now that I think of it more, since stack traces exist, there isn't even a need for that top-level try/except, for early prototypes. You can just write your main code, run it and let it fail, and fix the errors as you find them, by using try/except/finally etc.
Re:Why I’m not leaving Python for Go by wpietri on Monday September 24, 2012 @03:21PM (#4566432)
Yep.

I use the high-level error handler to let me know when a failure has some impact besides dumping a stack trace on my screen. E.g., failed web request, batch job barfing, etc. And to present the user with some reasonable "we're on it" thing.

Re:Why I’m not leaving Python for Go by hntester123 on Monday September 24, 2012 @05:35PM (#4567124)
Clear, and a good idea. Thanks.
Re:Why I’m not leaving Python for Go by ubershmekel on Monday September 24, 2012 @01:29AM (#4563342)
Very nice point, right on the money.

I believe I'm correct as no one has yet refuted the central problem discussed. The replies have mainly been justifying it.

Re:Why I’m not leaving Python for Go by belorn on Sunday September 23, 2012 @08:41PM (#4562685)
I would guess that most (99%) of C programmers are lazy or has an rapid programming style then. Its a rare thing to see C source code that even do the simple thing like wrapping every write/read/print call with a loop that detects eintr. In my years of programming, I have yet to stumble on a other programer who even knows that one should be doing this.

Looking at c libraries and their example code, almost every time, the example lacks error handling. Its almost like people avoid doing error checking in C code because of the cumbersome amount needed to be done in order to check each and every time. If an example code would include error checking, the number of lines can easy increase 3-4 times the original size.

Re:Why I’m not leaving Python for Go by kisielk on Sunday September 23, 2012 @11:11PM (#4563036)
In Go if you use the return value of a function you must also assign the error to something, either a variable or explicitly ignore it by assigning it to _. It was designed this way specifically to avoid the problem of not checking error conditions in C code.
Re:Why I’m not leaving Python for Go by osi on Monday September 24, 2012 @08:51AM (#4564350)
This breaks down when the method you call has no return value other than an error. In that case it is easy to forget.
Re:Why I’m not leaving Python for Go by xal on Sunday September 23, 2012 @09:31PM (#4562809)
That's true but also C's error reporting differs greatly between libraries. Each library has a learning curve in how it wants it's errors checked. From the top of my head, 10 years after writing any C code there is check against NULL - guess the error, check against minus values - lookup minus values in a table, check against 0 - call method to get error string and many more.

Go standardises this in a super clean way. Every method that can error will return an error. If you try to write a method that calls methods that can error and you don't return an error then you will be extremely aware of that. After a few days of Go it will be physically painful to write code that eats errors.

So what Go did was to take the return parameter style of error reporting, mix in multiple return values to make that not suck and then optimize towards the local maxima of programming comfort within this paradigm.

The result - as anyone who has been writing go for a few months can tell you - is something that works incredibly well. I'd say it works better then exceptions style all but that may be my personal preference.

Re:Why I’m not leaving Python for Go by slurgfest on Monday September 24, 2012 @12:04AM (#4563158)
I don't doubt that Go is usable and reflects an attempt to rationalize C's (non) conventions, which is a goal I appreciate. but it certainly isn't false for Python that 'the result - as anyone who has been writing [Python] for a few months can tell you - is something that works incredibly well.'
Re:Why I’m not leaving Python for Go by ams6110 on Sunday September 23, 2012 @08:56PM (#4562723)
To be fair, most sample code I've seen, regardless of language, usually does not include error handling. Why not? Probably because it would detract from the main point being illustrated.
Re:Why I’m not leaving Python for Go by davvid on Monday September 24, 2012 @04:47AM (#4563779)
In my years of programming, I have yet to stumble on a other programer who even knows that one should be doing this

That's a bold statement. Nice to meet ya! I'm no PC-Luser! ;-)

The PC-lusering problem is mentioned in "worse is better", so I would hope a fair number of folks know about it. Every good code base I've seen uses EINTR wrappers, but it is true that many folks I've met don't know about it.

Hey now.. it's not just C programmers, though. We have to use the same EINTR-retry loops in python too, sometimes:

https://github.com/git-cola/git-cola/blob/master/cola/decora...

I like C, Python, and Go. There's no reason to take sides, IMO. These are all highly effective tools.

Re:Why I’m not leaving Python for Go by pm215 on Monday September 24, 2012 @07:24AM (#4564079)
EINTR is a flaw in Unix's syscall model: it forces on every single application the responsibility for dealing with something that should have been handled at a lower level. That's unrelated to C's error handling style; it would be just as ugly if every write() call had to be wrapped in a try-catch block to retry when an InterruptedException was thrown, and people would still forget to write that ugly boilerplate.
Re:Why I’m not leaving Python for Go by jimbokun on Sunday September 23, 2012 @08:27PM (#4562654)
"Of course, you can add more code to deal individually with each of the exceptions in more robust ways, even to the point of wrapping each statement in its own try/catch block, but then it's no different in practice from returning error codes."

It is very different. With a try/catch block, you can see the normal logic flow of your code in one place, separated from the error handling logic. If you wrap each and every line that can have an exception with it's own try/catch block, then yes, that is pretty much the same as handling explicit error codes. Which is why I consider that poor style in languages that have exceptions.

Separating error handling code apart from the logic flow of normal operation is simply not possible with error codes as function return values.

Re:Why I’m not leaving Python for Go by to3m on Sunday September 23, 2012 @08:58PM (#4562727)
Um... errors ARE normal operation. Consult historical output from your C++ compiler, if you don't believe me!

(If anything, that should probably be "errors", quotes included, because what people usually mean by the term is "easily-forseeable occurrence that I couldn't be bothered to write the code for".)

Re:Why I’m not leaving Python for Go by barrkel on Sunday September 23, 2012 @10:03PM (#4562877)
Compiler errors aren't usually implemented as exceptions because compilers these days don't stop at the first error.

Exceptions are ideal for things that require aborting and unwinding to a point - usually a loop, like a server request handler or UI event dispatcher - high up on the stack. If the general behaviour is not to abort and unwind, it's not a good fit for an exception.

It's also why exception handlers should be very rare. There shouldn't be any more than a half-dozen in most programs. Error codes that need checking and aborting by hand at every function call boundary are a poor fit for replacing exceptions, because they optimize for the case where the error can be handled, rather than the usual case for exceptions, where the error cannot be handled.

Re:Why I’m not leaving Python for Go by stcredzero on Monday September 24, 2012 @03:43AM (#4563630)
> Error codes that need checking and aborting by hand at every function call boundary are a poor fit for replacing exceptions, because they optimize for the case where the error can be handled, rather than the usual case for exceptions, where the error cannot be handled.

From what I understand, the Go language team wanted to write robust servers, thus they wanted to "optimize for the case where the error can be handled."

Re:Why I’m not leaving Python for Go by to3m on Monday September 24, 2012 @07:43AM (#4564115)
My point was that programmers are happy to push the "error" handling off to some other part of the code, far away from the point at which the "error" arises, in some place that usually has no real idea how to handle it, or present it, or what have you. All as if there's some default privileged path where everything is running normally, and then this occasional strange special case that crops up now and again. Exceptions explicitly encourage this style of programming - keeping the error handling apart from the main logic is their very purpose.

But were programmers to consult the history of their compiler's output (representative summary: "ERROR ... ERROR ... FAILED ... WARNING ... ERROR"), it would be obvious that in fact errors are highly likely, even if you know what you're doing. So what makes the error case different from all the other cases?

Re:Why I’m not leaving Python for Go by barrkel on Monday September 24, 2012 @10:00PM (#4568131)
Errors in compilation are not exceptional; one of the main reasons to use a compiler rather than an interpreter is specifically to search for errors. So exceptions are a poor fit.

You're quite right that exceptions promote giving up control to a higher level. And that's the right thing to do for exceptional situations. The ultimate higher level is the programmer who's going to have to fix the bug, or the admin who needs to fix the configuration problem - because they are the two main classes of errors for which exceptions are great. (The third class is a logical abort, and depending on the language and how good its idioms support exceptions, this may or may not be good practice.)

You get rich information about the error, including a call stack, the ongoing operation gets cancelled as soon as it occurs rather than muddling onwards and causing more damage. If you can foresee the error such that you can write an error handler, using the method that throws exceptions is probably not the right one - unless it's unavoidable owing to race conditions, or impoverished libraries.

Re:Why I’m not leaving Python for Go by zmj on Sunday September 23, 2012 @11:31PM (#4563070)
Not at all. If a function can't or shouldn't be responsible for handling an error, it can return that error. The result is that the error passes back up the call stack until something handles it.

It's very similar to exceptions, except you have to consciously choose to do it. That's a virtue to me.

Re:Why I’m not leaving Python for Go by hmart on Sunday September 23, 2012 @09:08PM (#4562753)
Re:Why I’m not leaving Python for Go by hasenj on Sunday September 23, 2012 @10:03PM (#4562878)
> They create too many possible exit points

Irrelevant with go, thanks to the `defer` statement.

Re:Why I’m not leaving Python for Go by slurgfest on Sunday September 23, 2012 @11:51PM (#4563114)
I certainly agree that if you are thinking carefully about the code, either way should work just fine. As someone who likes C and Python I understand that both ways can make robust software, and it took me a little time to accept exceptions at all. More broadly, most of the languages that are widely used can write decent software.

I think this is a matter of what you prefer the program to do by default, when something clearly wrong has happened, but no error-handling code has been written: you may prefer such code to halt, or you may prefer it to keep on trucking.

If you use exceptions, you have to think about it IF you want the program to keep on trucking. Otherwise you can just let exceptional circumstances take care of themselves - if the program stops immediately, it cannot then behave incorrectly.

As a default failure mode, I do prefer the program to halt and decline to further cock up the situation (forcing me and my tests to deal with the condition) than for the program to silently swallow the error and continue as a default (forcing me to thoroughly check error codes everywhere up front out of pure fear that I will miss a condition).

This is just a convention and either one works.

If Go can become a better version of C then I might switch out C for Go. This isn't by any means going to cause me to give up Python because I use C for very specific reasons (when it is totally OK for reasons of speed or control to write a decent amount more code, and have it read more cryptically, and have to take care of many more low-level details).

Re:Why I’m not leaving Python for Go by babarock on Sunday September 23, 2012 @07:55PM (#4562584)
Re:Why I’m not leaving Python for Go by wonderzombie on Sunday September 23, 2012 @09:01PM (#4562738)
I basically agree with you. I think return codes are simpler, and exceptions appear simpler because we're used to them. In reality they are a magical, out-of-band mechanism compared to plain old return. I contend that local and explicit is more strongly correlated with simplicity than remote and implicit.

Put another way, verbose code can be simpler if it is direct and explicit — what happens is what's on the page — just as succinct code can be more complex if it is magical or implicit — what actually happens depends on who is calling it, say.

Re:Why I’m not leaving Python for Go by slurgfest on Monday September 24, 2012 @12:10AM (#4563176)
I used return codes before I ever used exceptions, and even chafed at exceptions. Exceptions CAN be simpler. It's just an expressive tool, it matters more what you do with it.

I do hate to read code which uses exceptions as a normal part of program flow, it's very GOTO-like and remote and implicit.

But I don't write code that way and nothing is forcing me to write code that way. When exceptions are reserved for really exceptional conditions where a requested performance CANNOT continue, they are used much less frequently, and more locally and explicitly.

In short I think the problem is a matter of philosophy more than language facilities, and the big differences are within-language rather than between-language.

The reason I like to have exceptions used as a convention is that I think a better default for programs which have not yet covered some corner case is for them to decline to run, rather than to run in dishonor.

Re:Why I’m not leaving Python for Go by mercurial on Monday September 24, 2012 @04:16AM (#4563706)
Say you need to migrate a database to a new schema. You need 10 SQL statements to do this. Each statement may fail, in which case you want to write stuff in a log and abort the transaction. In this case, wouldn't you agree that writing your statements in a try/catch/finally block would result in clean, easy to understand code, as opposed to adding explicit error handling after each statement?
Re:Why I’m not leaving Python for Go by acqq on Monday September 24, 2012 @04:38AM (#4563760)
I wouldn't agree, as when I'd code it in C I'd have a function callSql which returns false and write the code you describe as:

    if (    callSql( s1 )
         && callSql( s2 )
         && callSql( s3 )
         && callSql( s4 )
         && callSql( s5 )
         && callSql( s6 )
         && callSql( s7 )
         && callSql( s8 )
         && callSql( s9 )
         && callSql( s10 ) ) {
        endTransaction();
        return true;
    }
    logAndAbortTransaction();
    return false;

No need for exceptions at all, and it's very clean and clear what's going on.

I wrote the same code to my young exceptions-indoctrinated colleague who asked the same thing like you, and he couldn't believe at the start that that's all -- that much he wasn't used to a plain control flow. It's even obvious how it can be generalized for any sequence of commands:

    for ( int i = 0; i < n; i++ ) {
        if ( !callSql( s[ i ] ) {
            logAndAbortTransaction();
            return false;
        }
    }
    endTransaction();
    return true;
Re:Why I’m not leaving Python for Go by dagw on Monday September 24, 2012 @04:46AM (#4563776)
While this code is nice and concise, the problem is that you don't automatically know which call failed or what the error was.
Re:Why I’m not leaving Python for Go by acqq on Monday September 24, 2012 @05:26AM (#4563862)
If you can, write a more concise code with exceptions which will automatically show you which call failed and what the error was. If we include all the declarations, I claim that your solution wouldn't be shorter or more readable than my C variant I'll write, which would only declare error code values, or even return strings as error reports.

There's no advantage in exceptions, except when you use them for "hardware-like" generated exceptions (which is where they belong).

Re:Why I’m not leaving Python for Go by mercurial on Tuesday September 25, 2012 @04:30AM (#4569269)
That's very easy:

  void migrate() {
    try {
      callSql(s1);
      callSql(s2);
      ...
      endTransaction();
    }
    catch(SQLException ex) {
      logAndAbortTransaction(ex);
    }
  }
Now I have an exception to log, which means I have a stack trace which is going to tell me which statement failed rather having to play the guessing game. I may even get an explanatory message for free if the exception came with a message.

For me, having exceptions over return codes has a number of advantages:

* Within a single object, you get much more information (error message and stack trace). You need to return two different values if you need both a message and a return code

* You don't want to handle the exception at the call site? no problem, just propagate it up the stack. On the other hand, if you want to try the same thing with return codes, you need a way to differentiate the return codes due an error in your migrate() function and the error codes resulting from a given callSql statement.

* Which brings us to... another benefit: enforced compile-time checking of the exception. You can't write code that is going to check for a DogException when the callee throws a CatException. But it's very easy to check for -1 when the actual code is -2. Of course you can alleviate this somewhat using static constants, but it's still a safety issue.

Obviously, exceptions are not all roses either, whenever you need a new one, you need to create a class for it. But the workflow interruption is not greater by an order of magnitude than adding a static constant somewhere to represent your new error code.

Edited for better formatting.

Re:Why I’m not leaving Python for Go by acqq on Tuesday September 25, 2012 @09:09AM (#4570107)
Doing exactly the opposite from what I asked, you omitted all the declarations of all the classes you use. Note that if I use C++ I can also use the classes with the same semantic and that also contain error messages. The stack trace you mention is a debugger feature, not something your classes do by the language definition (I speak about C++, I don't know what's in Java). If you'd include all the code needed for your lines, you'll see that I have more freedom and not less expression possibilities. If you claim that you already have everything in libraries, OK, but C++ libraries without exceptions can have equivalent functionality. Exceptions are absolutely not needed to write the clean code that handles all the error conditions.
Re:Why I’m not leaving Python for Go by mercurial on Tuesday September 25, 2012 @10:18AM (#4570430)
The example code is not using a new exception, it's handling the callee's, the same way that your code does not use a new return code but relies on whatever the callee returns and does not include the code for "callSql".

I assume you are right about C++ exceptions (the little C++ I do doesn't use them). Modern managed languages incorporate the stack trace in the exception (including Java).

I'm not sure how you propose to have both return code and error message in C++, return a struct with an error and a message? This also does not answer my points 2 and 3 about handling errors occurring at different layers and compile-time checking.

Re:Why I’m not leaving Python for Go by acqq on Tuesday September 25, 2012 @05:25PM (#4572747)
I'm sorry but I firmly believe you completely missed the point. I wrote "If you can, write a more concise code with exceptions which will automatically show you which call failed and what the error was. If we include all the declarations, I claim that your solution wouldn't be shorter or more readable than my C variant I'll write" and you managed to omit everything I proposed as needed in order to demonstrate what is actually involved in exceptions -- not the use, but all the classes etc needed. In short, if you actually use library exceptions, there are thousands of lines of declarations. You can claim "but they are already there, I don't have to write them" still it's a library thing, not the "language as such" thing.

Errors can be handled at different layers (using normal control flow the same way as I already demonstrated -- simply writing ifs) and the error declaration can be checked at compile time in C++ exactly as C++ has (who would have thought that!) classes. Java also uses class infrastructure for that, exceptions are only "out of normal flow path" mechanism.

Re:Why I’m not leaving Python for Go by mercurial on Wednesday September 26, 2012 @03:02AM (#4574491)
Thousands of lines of declarations?

  import com.foo.SomeOtherException;

  public class MyException extends SomeOtherException {
    public MyException(String message) {
      super(message);
    }
  }
That's about as complicated as it gets (considering the example extends a custom exception instead of inheriting from java.lang.Exception). I'll note that your example doesn't declare any return code anywhere. Now, I'm curious to know how you would do the equivalent of this with error codes:

  public class MigrationException extends Exception {
    public MigrationException(String msg) { super(msg); }
  }
  
  public class SqlException extends Exception (
    public SqlException(String msg) { super (msg); }
  }

  public class Migration {
    public void migrate(Statement stat, int migrationNumber)
      throws MigrationException, SqlException{
      if (migrationNumber <= 5) throw new MigrationException("Wrong migration number " + migrationNumber, should be > 5");
      // throws SqlException
      stat.executeNonQuery("INSERT foo INTO bar");
    }
  }

  public class MigrationRunner {
    public void run(Statement stat, Migration migration, int migrationNumber) {
      try {
        migration.migrate(stat, migrationNumber);
      }
      catch(MigrationException ex) {
        migrationLogger.error("Bad migration", ex);
      }
      catch(SqlException ex) {
        migrationLogger.error("DB error", ex);
        sqlLogger.error("Error during migration", ex);
      }
    }
  }
I'm on purpose not reimplementing an SQL driver here :)

I'm not quite sure why you are arguing about "error declarations which can be checked at compile time in C++". Sure, C++ has exceptions, but I thought you were trying to make a point about return codes, not C++ exceptions vs language X exception. My point, on the other hand, is that it's very easy to do this:

  #define SQL_ERROR 1
  // whoops, same error code due to copy-paste
  #define MIGRATION_ERROR 1

  void handleError(int errorCode) {
    // Too bad, this was actually an SQL error
    if (errorCode == MIGRATION_ERROR) {
      ...
    }
    else {
      // We'll never enter this branch
      ...
    }
  }
No compile-time check for that. Or even:

  #define MIGRATION_ERROR 1
  #define SQL_ERROR 2

  void handleError(int errorCode) {
    // I actually meant 2 here
    if (errorCode == 1) {
      logSqlError();
    }
  }
Re:Why I’m not leaving Python for Go by dbaupp on Monday September 24, 2012 @05:35AM (#4563874)
The loop variant does know which call failed, and could easily be modified to know what the error was (if the underlying callSql had more than just a boolean failed/success return value).
Re:Why I’m not leaving Python for Go by JulianMorrison on Sunday September 23, 2012 @08:09PM (#4562624)
The following illustrates how you use Go errors as if they were exceptions:

    func A() error {
        err := compute.Something()
        if err != nil {
            return err
        }
        return nil
    }
Throwing errors up the return chain using error values is really very little different than throwing up the return chain using exceptions, except that now there is only one way to return, and it is always clearly marked. You return where you say "return". And you return what you said you would.
Re:Why I’m not leaving Python for Go by smosher on Sunday September 23, 2012 @08:53PM (#4562718)
What am I missing here? This appears to be fully in-band and contains a redundant code path (constituting a NaN bug in languages with incomparable NaN—no idea if that applies to Go) for no apparent reason.
Re:Why I’m not leaving Python for Go by JulianMorrison on Monday September 24, 2012 @03:25AM (#4563588)
What you're missing is that I'm showing how error throwing and error returning are functionally the same, when you have a standard error type, multiple valued return, and an idiom of returning errors you chose not to handle.
Re:Why I’m not leaving Python for Go by smosher on Monday September 24, 2012 @08:59PM (#4567944)
Sure, you can handle errors and you can explicitly pass the buck. That's no different than what we do in C. Exceptions are out-of-band (from a regular return value), and what you're talking about is entirely in-band. What you're doing, functionally, is returning a tuple. This is as old as the sun and nothing at all like exceptions.

I'm not sure what you think idiom means (Hello, my name is Inigo Montoya), but you never need one to do anything in code. In human language they capture some context and their meaning must be understood by rote or in terms of that context, but in code they are entirely explicit and work just as well before and after becoming idiomatic—which is solely a form of classification that people use and computers don't.

Re:Why I’m not leaving Python for Go by JulianMorrison on Tuesday September 25, 2012 @07:04AM (#4569680)
Idiom just means "a standard way to do things, that everyone recognizes and uses".

Normal exceptions, the kind that unroll the stack (and not deep magic like call/cc) are only "out of band" as an optimization. There is no behavioral difference between "save the last place you decided to handle errors, and jump there directly unrolling the stack at once" versus "unroll the stack by a series of buck-passing in band error returns, until you get to the last place you decided to handle errors". A compiler could implement exceptions by silently transforming them into Go form. And a Go compiler could silently transform buck-passing into traditional exceptions.

Re:Why I’m not leaving Python for Go by smosher on Tuesday September 25, 2012 @05:04PM (#4572653)
In particular idiom does not mean something deliberately entered into the language to solve a particular problem—that's just regular semantics. Idioms are by nature emergent. For example I might be conscious of 3 idioms among all the languages I know (which is much more than 3), yet I write idiomatic code because I know the languages well. In fact, outside of Go circles no one talks of idioms, they talk of idiomatic code.

Who cares about compiler transformations? The issue is the semantic difference between return codes and exceptions. Nobody is asking for exceptions because they can't or don't know how to get to the correct scope to handle their errors, they're asking for them because they don't want to write all the boilerplate necessary to do so.

And yes, you can transform exceptions to chained returns. That would be a lot of work for terrible performance. You can't do the other transformation though. It would require being able to statically analyze the code path to determine where the errors are eventually handled, which is impossible in the general case.

Re:Why I’m not leaving Python for Go by azth on Sunday September 23, 2012 @09:39PM (#4562821)
How is that different from

    func A() error {
        return compute.Something()
    }
Re:Why I’m not leaving Python for Go by JulianMorrison on Monday September 24, 2012 @03:22AM (#4563579)
My point is that whether it's "A() error" or "A() (int, error)", whether it calls one function or three, what it's doing with the error is throwing it up the line, rather than handling it locally. Exactly as if it had said "throw err". So yeah, your version is what I'd shorten it to in practise, it just wasn't quite so illustrative.
Re:Why I’m not leaving Python for Go by zmj on Sunday September 23, 2012 @11:36PM (#4563080)
The example is easier to extend to include additional logic after the call or another return value.
Re:Why I’m not leaving Python for Go by dkersten on Monday September 24, 2012 @07:14PM (#4567594)
Its not really the same though. The two differences I can think of offhand are that 1) you have to manually pass error up the call stack until you want to handle it, while exceptions are automatically propagated, meaning that you don't have to remember to do this until the point where you actually want to handle the error and 2) exceptions usually contain a stack trace to where they were raised while this method won't (without additional work anyway), so contextual information is lost.
Re:Why I’m not leaving Python for Go by makmanalp on Sunday September 23, 2012 @11:29PM (#4563067)
Or, ya know, you just do:

  if (!herp_derp()){
  ...
  }
or

  if (herp_derp() > 0){
  ...
  }
and don't actually check any of the error cases that you should be checking, like return = -1, -2, -3 etc.