Live data from Hacker News

Ten years of “Go: The good, the bad, and the meh”

blog.carlmjohnson.net

221–230 of 305 posts

Re: Ten years of “Go: The good, the bad, and the meh”

#221
post #124

The biggest go problem in practice is ironically omitted in both blog posts: Verbosity of error handling! There should be a shorthand for returning if last ret value is non-nil in one line. Otherwise all you code is littered with: if err != nil { return err } and it makes it four times as long and way less readable as a result. This needless verbosity really reminds me of Java. Also, go fmt is not opinionated enough!…

Your code shouldn't be littered with that though, those errors should be wrapped or have some kind of logging/handling associated with them. If you find yourself just returning err all the time, you're not doing it right, IMO.

If only a language could have a built in feature to propagate an error up the call stack, recording its context as it goes!

It's always surprised me how negative of a reception checked exceptions had, since they provide the forced handling (or explicit propagating) of (value, err) or Result, but with an automatic stack trace and homogeneous handling across the ecosystem

I imagine some of the disdain in Java specifically came with how unergonomic they are with lambdas. Either you don't allow them at all, like in most standard library functional interfaces, or you do, but now every caller has to handle a generic Exception. I guess what was really needed was being able to propagate the "check" generically, e.g.

   T higherOrder(Supplier fn) throws E {
    return fn.call();
  }
So a call site of higherOrder would only be checked as far as fn is

I'm unsure if that's even possible to do (and if other languages have done it) or if it leads to undecidability. I'm very rusty on PLT

Re: Ten years of “Go: The good, the bad, and the meh”

#222
post #25

Earlier quoted context omitted.

Not just networking but focusing on concurrency. In before if you needed to make a highly concurrent network app you had to get into asynchronous programming that generally makes code looks shit (or at least slightly worse) and harder to debug. With Go and goroutines taking IIRC around 8k for start you can "just" spawn as many of them as there are connections and write your code as if it was serial one. Add some half…

Erlang had a better concurrency story than Go, and better error handling. But alas marketing wins.

Marketing, lol. Erlang is a functional language. Functional. That alone has prevented its widespread adoption.

Re: Ten years of “Go: The good, the bad, and the meh”

#223

Earlier quoted context omitted.

Prior to generics we relied heavily on dynamic typing via interface{}, for example: BulkInsert(db *sql.DB, objs []interface{}) This unfortunately meant that any time you had []Foo.. you had to allocate a new []interface{} and copy over the items. Now a function like that can look like: BulkInsert[T any](db *sql.DB, objs []T) And we're not wasting CPU cycles to copy the slice of []Foo. I'm struggling to see how that's…

Dynamic typing via interface{} is also huge Go code smell though, so... Generics are definitely better for you. But I would say the overall pattern you're employing of bulk inserting different kinds of data structures with one function is the problem. Of course, I don't know your code so I'm sure you have a good reason for choosing what you did, but a BulkInsert of Any certainly made me raise my eyebrow.

But why is it a problem (assuming the database in this example can handle any type)? If I'm writing a function that returns the 5th element of a list, I will always write that using generics, even if I know it's only used with one type (right now). Not only is it basically free (` T getFifth(List)` is really not any more complicated than `Foo getFifth(List)`), it's also a separation of concerns. The logic is just about the container, so no need to complicate it with a "red herring" of a forced type

Re: Ten years of “Go: The good, the bad, and the meh”

#224
post #30

Earlier quoted context omitted.

a, err := f() if err != nil { return } a, err = f() This will compile.

a isn't used so it won't ;p Honestly the thing that I think lacks more is macros. With macros it would be trivial to write a := Must!(f()) that * assigns last return value to err * calls return with that error if it is not nil

Macros are a lazy design cop-out. They subvert the entire point of having a language in the first place - a shared understanding.

Re: Ten years of “Go: The good, the bad, and the meh”

#225
post #72

Earlier quoted context omitted.

Go really is great. There was a big argument around a new project we were starting whether to do Go or Clojure. What we did to settle the debate was to ask an entry level dev that was just starting if he was interesting in writing two sample applications in each language, having known nothing of either. Nothing complicated but touched enough points (HTTP endpoints, database interaction) A full day later was still try…

As a method for choosing a language, doesn't this just inherently skew to the smaller and more simplistic one, which may not necessarily be the best for all tasks or over a longer run where the techniques of the more involved language could be learned? It's like hiring a new farmhand and saying, "here, dig two 3 foot holes, and we'll see what takes you longer, this shovel or an excavator you have no training or exper…

It feels to me more like giving them the choice of two excavators one with many more options that are unnecessary and one with simple easy to grok basic controls

Re: Ten years of “Go: The good, the bad, and the meh”

#226

Great article. Go may have generics, but because old Go code doesn't, and the standard library doesn't, it still feels like the language doesn't sometimes.

Correct, a new language feature doesn't magically inject itself into all existing code. This simple fact is sadly commonly missed by many.

Re: Ten years of “Go: The good, the bad, and the meh”

#227
post #213

Earlier quoted context omitted.

I still don't know what people mean by "obvious" code. Yes, there are people who create a mess with abstraction. This happens in every language, in Java people create FactoryFactories, in Haskell people play type tetris, in Ruby, people abuse metaprogramming and in Go, I assume some people go overboard with code-gen. But that said, I suspect many people, when they say, "obvious code", they mean "I can easily understa…

> Yes, there are people who create a mess with abstraction. This happens in every language, in Java people create FactoryFactories, in Haskell people play type tetris, in Ruby, people abuse metaprogramming and in Go, I assume some people go overboard with code-gen. It's possible in any language and yet some languages' codebases are consistently worse than others ;) If you create a culture of cleverness, implicitness…

I'm not sure why you think that quoting random HN users proves anything except personal opinions of specific people? These are fine, but other people have other opinions.

I don't oppose the "principles" you've quoted, but they would just as easily apply to e.g. Haskell (maybe except for the "there's only one way to do it" which however has never been true of any language, including Python).

I feel like you missed my larger point. It's not terribly difficult to write code that you can understand line by line. It's incredibly hard to write a huge code base in a way that you can reason about many code paths simultaneously, however. That's where the abstractions start to make sense.

I don't understand why people think that those facilities were created just to piss people off? People were facing real problems. Yes, sometimes the cure is worse than the disease. Use abstractions judiciously and by employing common sense. That doesn't mean you should never use them.

I've seen over- and underabstracted code (as well as just plain wrongly abstracted code). Both of these situations really suck.

Honestly, what annoys me a bit here is your smugness. It seems as if you feel you've figured out how to write good code, and all the other idiots who use Ruby, Java, etc. haven't. But I don't believe you. Nobody in this industry knows how to write "good" code. I don't even think we know what "good" code is. The most we can do is try our best, learn about better ways to do things, discuss approaches and use our judgment.

Re: Ten years of “Go: The good, the bad, and the meh”

#228
post #194
post #158

Earlier quoted context omitted.

In ML-lineage languages (including Haskell) you almost never need any type annotations whatsoever, at least not unless you’re poking around at the fringes of those languages (GADTs, various GHC extensions). Type annotations for top-level definitions are often encouraged for readability and better error messages, but the compiler can almost always figure everything out itself.

From my experience, such type inference systems are awful in practice. Rust designers tried to do something like that initially but quickly realized understandability suffered greatly. You really do want to specify types manually, at least at boundaries, e.g. in function definitions. > Type annotations for top-level definitions are often encouraged for readability and better error messages, but the compiler can almos…

Right, global inference turns out to be too much inference. Function boundaries are a convenient place to draw a line.

As usual C++ choose to something much weirder and more dangerous. Instead of inference C++ can deduce types, in some cases there's no way to write a type's name so you have to deduce types, and they can be deduced at the edges of functions however unlike inference it's not an error to have ambiguity, in some cases deduction may choose one of the possibilities that it liked better even if that's astonishing for you.

Because Rust's functions must tell you their types explicitly, and because some types can't be named specifically, the result is that in Rust you have to write these functions polymorphically, even if in practice there's only one possibility. In C++ you can write the non-polymorphic function, despite not being able to say the name of the type. How do you document that? It's OK, C++ doesn't require you to provide even halfway usable documentation.

Re: Ten years of “Go: The good, the bad, and the meh”

#229
post #191
post #46

> Again, it shows how things have changed that I praised Go’s type inference as an advance in the state of the art, but now the Hacker News crowd considers Go’s type inference to be very limited compared to other languages. "You either die a language nobody uses or live long enough to be one people complain about." This rubs me the wrong way. Even back when Go first came out, anyone who knew anything about programmin…

> Even back when Go first came out, anyone who knew anything about programming languages rolled their eyes at pretty much everything about Go's type system, including the inference. The fact that it was even a point of concern shows how misguided the PL community is. Advancing the state of the art is not the goal, producing a tight, clean design is. > Just because Sun couldn't figure out how to do it in the 90s doesn…

Go comes out, some Go cheerleader describes its decidedly not-state-of-the-art type inference engine as "state-of-the-art", I point out that it was hardly state-of-the-art, the Go cheerleaders come along and say "why do you even care if it's state-of-the-art?". Am I getting this right?

Re: Ten years of “Go: The good, the bad, and the meh”

#230
post #127

Earlier quoted context omitted.

Even back when Go first came out, anyone who knew anything about programming languages rolled their eyes at pretty much everything about Go's type system, including the inference. The Go team was populated by people who had created one of the most influential languages of all time, C. Who created the new language based on theories about how to encourage good engineering practice. Theories that they were able to test…

C is also a very low-level and close to the machine language. Just because you can build a microchip doesn't mean you can build a spaceship and vice versa. So I'm not surprised about that they e.g. left out generics and said they did so because they didn't know a good or right way to add them to the language. They were honest at least which I value a lot. As to the success of Go that you mention. Well, let's be hones…

> Just because you can build a microchip doesn't mean you can build a spaceship and vice versa.

A recent incident of a submersible built by someone with aerospace experience comes to mind.

Post reply on HN