Live data from Hacker News

Why I’m not leaving Python for Go

uberpython.wordpress.com

211–220 of 245 posts

Re: Why I’m not leaving Python for Go

#211

Earlier quoted context omitted.

>In the hands of someone who knows what's going on, programs get much simpler I never really got this argument. With RAII types that have value semantics (ala shared_ptr) what is so difficult about memory management in C++? I guess there are reference cycles, but weak_ptr can help there. Manual ref-counting (like a COM AddRef/Release pattern) can be tricky, but that is where attention to detail, code reviews and basi…

In my experience of web server apps, it's been fairly easy to guarantee that either the whole request succeeds, or - if there was an exception - every change is rolled back. Both user state and database state has been transactional, and state that lived on in memory in between requests was either read-only or caches. In UI apps, it's much much harder to guarantee transactional semantics unless you're using persistent…

>If you don't yet understand why GC increases productivity, it's an epiphany you'll need to look forward to.

Oh I fully understand/agree with that, I just don't find C++ memory management to be too hard. The concurrency concerns pointed out by others are true, though. Whether they (the concerns) are offset by the lack of deterministic destruction and the extreme triviality of creating reference chains that root things far longer than needed due to the root being live while the rest of the chain should be dead, is another question.

As you pointed out, in some domains transactional code is fairly straightforward, or at least tractable without inducing massive depression. In some other domains, not so much :)

Re: Why I’m not leaving Python for Go

#212
post #201
post #181

Earlier quoted context omitted.

> As usual in these threads about Go, I really wish people would consider Haskell as a nice alternative. A lot of people write Haskell off as "academic" or "impractical", which I feel is not an entirely fair assessment. As someone with 10+ years of programming experience in the industry but no formal college education, I see the problem with Haskell (and other, similar functional programming languages) that in order…

That's true, and there's no shame in not knowing a language yet, but I'd still recommend you check it out. It's almost like relearning CS.

I tried, and failed. Multiple times. Systems that are complicated are not really appealing.

Re: Why I’m not leaving Python for Go

#213
post #194

Earlier quoted context omitted.

But if there was an error, WHY WOULD YOU EVEN BOTHER?! Read the documentation what it says about the value in case of an error, and stop inflating a non-issue.

Human beings are capable of making mistakes, that's the entire point. If you forgot to check the error code in go, then you will end up using that non-float float that shouldn't exist as if it were really a float. In a decent language, you get either an error or a float, you have no way to accidently use the float if an error occurred.

> If you forgot to check the error code in go, then you will end up using that non-float float that shouldn't exist as if it were really a float.

Consider the following code:

   foo, err := strconv.ParseFloat(...)
If you don't handle the error (e.g. by forgetting), the compiler will show an error because you declared err, but didn't use it.

If you write

    foo, _ := strconv.ParseFloat(...)
instead, you deliberately choose to ignore the error.

> In a decent language, you get either an error or a float, you have no way to accidently use the float if an error occurred.

Making these specifics a criteria for decency is nothing but arrogance.

Re: Why I’m not leaving Python for Go

#214

Earlier quoted context omitted.

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.

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/fin…

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

#215
post #156
post #79

Earlier quoted context omitted.

So instead of writing x, err := something() if err != nil { handleError(err) } n, err := somethingElse(x) if err != nil { handleError(err) } andSoOn() you could write switch x := something() { case error: handleError(err) case string: switch n := somethingElse(x) { case error: handleError(n) case int: andSoOn() } } ?

Yes. The advantage of the second form is that x := something() n := somethingElse(x) andSoOn() no longer compiles. Obviously you would also want some syntactic sugar to make it look nice, but that's quite simple.

  x := something()
  n := somethingElse(x)
  andSoOn()
This won't compile in Go.

  x, err := something()
  n, err := somethingElse(x)
  andSoOn()
This won't compile in Go as well (compiler requires that you use the variables you declare).

You can only explicitly ignore errors:

  x, _ := something()
  n, _ := somethingElse(x)
  andSoOn()
Except for one case where error is the only returned value.

   err := fmt.Println("")
   _ = fmt.Println("") // ok
   fmt.Println("") // ok

Re: Why I’m not leaving Python for Go

#216

Earlier quoted context omitted.

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/fin…

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.

Clear, and a good idea. Thanks.

Re: Why I’m not leaving Python for Go

#217
post #213

Earlier quoted context omitted.

Human beings are capable of making mistakes, that's the entire point. If you forgot to check the error code in go, then you will end up using that non-float float that shouldn't exist as if it were really a float. In a decent language, you get either an error or a float, you have no way to accidently use the float if an error occurred.

> If you forgot to check the error code in go, then you will end up using that non-float float that shouldn't exist as if it were really a float. Consider the following code: foo, err := strconv.ParseFloat(...) If you don't handle the error (e.g. by forgetting), the compiler will show an error because you declared err, but didn't use it. If you write foo, _ := strconv.ParseFloat(...) instead, you deliberately choose…

>If you don't handle the error (e.g. by forgetting), the compiler will show an error because you declared err, but didn't use it.

But if I make a mistake like I mentioned previously, I could very well use err, thus not getting a compiler warning, and still also use foo, which is a whoknowswhat. It should be an Either, not two seperate return values.

>Making these specifics a criteria for decency is nothing but arrogance.

Having opinions is not arrogance. You should consider that when someone shares their opinion, they are not declaring that everyone everywhere must acknowledge it as a universal truth.

Re: Why I’m not leaving Python for Go

#218

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…

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". An…

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

#219
post #57

Earlier quoted context omitted.

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.

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.

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

#220
post #169
post #73

Earlier quoted context omitted.

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 shoul…

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. Excepti…

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.

Post reply on HN