Live data from Hacker News

I want off Mr. Golang’s Wild Ride (2020)

fasterthanli.me

461–470 of 477 posts

Re: I want off Mr. Golang’s Wild Ride (2020)

#461

Earlier quoted context omitted.

I've ran into bugs multiple times because I ignored an error result, or overwrote the "err" variable and swallowed an error. Errcheck helps a bit. Other languages that have exceptions that bubble up the stack have a few advantages (easier to instrument with monitoring, stack traces and line numbers out of the box) but developers often misuse error handling as flow control

> I've ran into bugs multiple times because I ignored an error result, or overwrote the "err" variable and swallowed an error. Errcheck helps a bit. Any reasonable code review process would catch these (very obvious) problems.

my golang code is littered with err handling etc, it’s easy to miss something over the course of dozens of prs. This is something best caught at compile time or by a linter. Or tests which I am often lacking

I find code review unreliable at best for catching bugs or logic errors, but depends on the reviewer

Re: I want off Mr. Golang’s Wild Ride (2020)

#462
post #416
post #120

Earlier quoted context omitted.

Don't fall prey to an ad-hominem argument - I don't think your article negatively hints at any kind of 'this is a Rust fanboy-made praise text' and it saddens me that a genuinely legit article like this needs to have the author defend himself like this. Your points were well explained. Go has several serious warts which, in my own opinion, are showstoppers, and you are comparing it to a language which is somewhat new…

>It is very clear how badly bolted and rushed generics were in Go. They were designed with the help of type system experts like Phil Wadler: https://arxiv.org/abs/2005.1171 Not sure why you think they were 'rushed', given the timeframe involved.

I don't follow. The Arxiv link you provided lacks a single mention to the name you mentioned... and even without knowing him, I can believe you that Mr. Wadler is probably a prominent and important type-theory researcher. But unless your argument is about a reverse ad hominem (citing an important name for the sake of "important person participated in this, cannot criticize design/execution"), I cannot see the point of this at all.

Explaining further: When I mentioned "rushed", it was clear for most of us that "generics" appeared quite late in the Golang picture, and it did only rise in priority when they figured they were losing market share to 15yo+ languages because of this single design flaw. Also, as soon as it became a heated topic, the working group started racing to have it included as soon as possible. As early as Go 1.17. Then, in the last moment, it got pushed to 1.18 because several deep questions remained open. Why the need to race it so much for .17, I ask? They probably felt it was 'too late' so must get it out of the door as soon as possible, even build hype for it on .17 in several changelogs even though it was clearly not ready (and those who were following the working group discussions know that it would NEVER be done for the .17 release).

Hope I was able to shed some light on the reasoning and word choices I had in my previous answer.

Re: I want off Mr. Golang’s Wild Ride (2020)

#463
post #462
post #416

Earlier quoted context omitted.

>It is very clear how badly bolted and rushed generics were in Go. They were designed with the help of type system experts like Phil Wadler: https://arxiv.org/abs/2005.1171 Not sure why you think they were 'rushed', given the timeframe involved.

I don't follow. The Arxiv link you provided lacks a single mention to the name you mentioned... and even without knowing him, I can believe you that Mr. Wadler is probably a prominent and important type-theory researcher. But unless your argument is about a reverse ad hominem (citing an important name for the sake of "important person participated in this, cannot criticize design/execution"), I cannot see the point o…

>Then, in the last moment, it got pushed to 1.18 because several deep questions remained open.

Delaying a feature to make sure that it's implemented correctly is the exact the opposite of rushing it!

I think you are vastly overestimating the influence of internet message board drama on the actions of the Go core team. In any case, you provide no evidence to support your claims about their motivations.

I'm not sure what happened with that Arxiv link, but here is another link to the paper I was thinking of: https://homepages.inf.ed.ac.uk/wadler/papers/fg/fg.pdf The fact that a leading researcher in type systems was a key participant in the effort suggests that this was a carefully thought through proposal (not necessarily perfect or beyond criticism, but not a rush job). Of course, if you think otherwise, you can point to any specific flaws in the paper.

>reverse ad hominem

The term you're looking for is 'argument from authority'. But argument from authority isn't really a fallacy. It's perfectly sensible to trust authorities, within reasonable limits.

Re: I want off Mr. Golang’s Wild Ride (2020)

#464

Earlier quoted context omitted.

> It is acceptable for code whose maintainers value readability and simplicity over everything else. Errors-as-return values are less readable than conditions, not more - there's literally more visual noise on the screen. And if you want "simplicity", don't use a computer. Computers are intrinsically complex devices, users desire features with complex implementations, and our job as programmers is to manage complexit…

> Errors-as-return values are less readable than conditions, not more - there's literally more visual noise on the screen. No. When you make a function call, and that call can fail, then the happy-path and the sad-path are both things that you need to manage as a caller. Happy-path and sad-path are two equivalent states that both need to be accommodated by the program logic. Error handling code is not "noise". It is…

> No.

Yes. There is literally more visual noise on the screen. This is not up for debate - more pixels are lit on the monitor you are looking at.

> When you make a function call, and that call can fail, then the happy-path and the sad-path are both things that you need to manage as a caller.

False - the direct caller is not responsible for error-handling, in general - some transitive super-caller will be. Errors as return values needlessly generate this visual noise for every caller, when not needed, in addition to introducing aforementioned coupling.

> Error handling code is not "noise". It is equally important to success-path code.

You're misunderstanding my point. I never said that error-handling code is noise - it isn't. What is noise is forcing every single function call between the appropriate error-handling point and the error location to have extra useless junk. When there's an error, you should see exactly two things in your codebase: some stuff at the point where the error is thrown, and some stuff at the point where the error is handled - and, given that the place where the error should be handled is rarely the direct caller, you should see nothing in between.

Re: I want off Mr. Golang’s Wild Ride (2020)

#465

Earlier quoted context omitted.

Errors as return values is only acceptable for code that is so performance-sensitive that you aren't allowed to do dynamic memory allocations. For everything else, conditions+restarts are the correct answer, because errors-as-values restricts you to a single error-handling strategy and couples high-level code to low-level code as a result.

Error handling is basically orthogonal to performance. If a function call can fail, it should return an error, and that error should be managed by its caller. Any other approach means callstacks are unpredictable, which makes a program way way harder to model.

> that error should be managed by its caller

Objectively false. Correct answer: the error should be managed by the code that makes sense to handle the error.

> Any other approach means callstacks are unpredictable

Also false. I use conditions regularly, and my callstacks are very predictable - errors bubble upward through the call tree until they're handled. There's nothing simpler.

> which makes a program way way harder to model

Also false. I have no problem at all modeling and understanding my code rife with conditions.

Re: I want off Mr. Golang’s Wild Ride (2020)

#466
post #39

Golang is great because it was the first to include excellent tooling in addition to the language (strict compiler, linting, non-customizable gofmt, package manager, good html docs, online playground, etc.) It’s undeniable that it brought a lot of good ideas that languages like Rust borrowed. Golang is still undefeated in terms of battery included. Its standard library is top notch and full featured. On the other han…

I don't believe Go was the first language to include "excellent tooling." Ruby on Rails, for instance, has had excellent tooling since the dawn of time, and I'd argue that Ruby on Rails' and Elixir's tooling are superior to Go's.

what elixir tooling are you using? I absolutely deplore writing elixir because I just find the tooling atrocious

Re: I want off Mr. Golang’s Wild Ride (2020)

#467
post #39

Golang is great because it was the first to include excellent tooling in addition to the language (strict compiler, linting, non-customizable gofmt, package manager, good html docs, online playground, etc.) It’s undeniable that it brought a lot of good ideas that languages like Rust borrowed. Golang is still undefeated in terms of battery included. Its standard library is top notch and full featured. On the other han…

Java and Erlang both have phenomenal tooling, especially when it comes to runtime introspection and debugging.

I've had nothing but negative experiences debugging elixir honestly. In a large project, trying to step debug is just way too slow

Re: I want off Mr. Golang’s Wild Ride (2020)

#468

Earlier quoted context omitted.

This is correct (in that the most simplistic case is try-catch). However, the difference between a try-catch and conditions / restarts is that when one signals a condition (exception), the restart (catch) has a continuation from the condition. This allows you to inject an expression into the location where an exception occurred and "restart" your code from that point. Whether you do such a thing or not depends on the…

> Going farther than this, conditions and restarts are really just a fancy way of packaging delimited continuations. I don't personally know any non-Lisp language that has attempted to package these concepts (maybe Dylan, which is a Lisp-like in its own way but without the syntax?). Dylan does have a condition system, but it’s basically a Lisp without the parens, so probably doesn’t count. On the other hand, algebrai…

> Huh? I don’t know why you’d say that, if anything I think it’s the Either err t / Result style that is more expression-focused (I mean, it even originates in Haskell :). I wouldn’t even call Common Lisp particularly expression-oriented, honestly, not unless we’re comparing with plain old C and not Rust.

I think that's exactly what I mean. The vast majority of languages (including golang, in TFA) use statements for dealing with exceptions. Rust also had try-catch, but has long since removed that syntax.

Anyways, the reason I said it is because it is not clear what to do when one wants to restart a statement. There are plenty of non-expressions that can throw, and usually it's not thought about deeply, but from a language semantics point of view one does need to have an idea of how to engage with it. For example, if you wrote:

    with open('somefile') as f:
        for line in f: 
            # ...
in Python, and had to deal with a restart during `open`, how do you manage this? The naive answer is to just return the continuation at `open`, but the "with" statement may have contextual setup. For example, `open` might be fine during `__init__`, but may have failed in `__enter__`. If you "restart" in `__enter__`, you need to deal with the partial state. Expression-based languages don't really have this issue because the call stack is usually clear (there's no magic under the hood). Similar analogues would be the `using` keyword in C#, or perhaps even lambda-expressions in C++. The abstraction in the code is separated from the execution of the restart, so it gets kind of gross as a language implementer in terms of not having to have very specific places where restarts can and cannot be.

This is a good reason why Rust / Haskell don't package these and just use Either / Result instead. If you have a bunch of types that you didn't write, injecting a restart into any failing code now brings a question of: "Can you safely inject types into a restart for code that you do not have access to?" and the answer is often no. The visibility rules in Rust make this a non-starter, and in Haskell you have a problem of mutability as well. A condition may be triggered at a point where IO could be injected, and so many of the language semantics would be in question. I suspect the type definitions for a restart in any arbitrary location in the code would be pretty hard to write, so maybe this is an open research area in Haskell already, but I doubt it'd be as ergonomic.

Re: I want off Mr. Golang’s Wild Ride (2020)

#470

Earlier quoted context omitted.

> Density divorces us from context a lot more than physical distance on a screen. You mean " unreadable code divorces us from context". "Density" doesn't have anything to do with it until you get to the point where your code is so dense as to become unreadable. Moreover, "physical distance on a screen" is a strawman. The options aren't density and distance, they're density and not being able to see the code on the sc…

> You mean "unreadable code divorces us from context". "Density" doesn't have anything to do with it until you get to the point where your code is so dense as to become unreadable. As density increases, the difficulty of parsing also increases. At a certain, relatively early point, that difficulty rapidly exceeds the costs of scroll-and-scanning. > Moreover, "physical distance on a screen" is a strawman. The options…

> At a certain, relatively early point, that difficulty rapidly exceeds the costs of scroll-and-scanning.

"Relatively early" is an unquantifiable statement, but regardless, that point is very far away from Go's design & generally accepted style, so this statement isn't really relevant to the conversation.

Regardless, scrolling exists by necessity, because some things simply can't fit on a single screen. It's still clearly always better to not scroll than scroll, assuming you aren't packing things in super tightly - I shouldn't have to provide evidence for this, but the fact that people don't just randomly clip text so they can add scrollboxes everywhere should be sufficient.

This is all a distraction from my last statement in my previous comment:

> Seeing context is always better than not seeing context, assuming equal readability. Go's verbosity is both less readable and less dense than that of other, better-designed languages.

Post reply on HN