Hacker News new | ask | show | jobs
by jnordwick 2540 days ago
Go's not existent standard library is almost a deal breaker for me.

The lack of even a dynamic array (c++ vector, Java arraylist) means you write a lot of 2-3 lines of slice notation phrases that require stopping and thinking about indices you wouldn't need to in other languages (and creating a lot of zero length slices for boundary conditions that shouldn't be needed). Also no balanced tree is a big issue (googles side implemention sucks in that the comparator cannot be passed in).

I recently tried to write some small library functions using sqlx to do arbitrary sql queries and then some munging of the results before returning it. It was extremely difficult.

The language feels half done at times. I find it hard to believe that Google used it much internally before releasing it. So many unfinished corners.

Generics would go a long way to fixing some of these issues.

While the ahead of time compilation is nice and had lead to me using it for things that need fast startup (some shell like scripts and literally old school cgi), it often seems like a worse Java.

If you don't like Java's verbosity, go's from my small use is about twice as bad. 300 lines of go does surprisingly little - part of this is gofmt's fault though.

Also, does anybody know of good performance tests between Java and go? I mean like well written and optimised. Most tests over I've are very poorly written and do dumb things like include hotspot startup and compilation times. Hotspot can generate some very slick code, but it just takes 10k passes to get up that point.

4 comments

I (and seemingly other people) consider https://www.techempower.com/benchmarks to be a good set of performance benchmarks for use cases many people around here would be facing. I guess they haven't been updated in nearing a year though. Go does reasonably well but apparently gets beat by Java.

More generally. I like the idea of community driven benchmarks where each community tries to make representative, performant samples to realistic problems. All too often you get an expert in one language making a benchmark against a language they are not experienced with and getting really improper results.

I don't do any a lot web stuff but most of my go code is quick hacks for data analysis or display but this is still really interesting.

I had a feeling go was slow, but I didn't expect such poor performance numbers. Some of that is probably the heavy reliance in reflection. For example they json parsing you need to go to the bottom of the list to find a go program, and go's json library makes extensive use of reflection and tags to guide the parsing.

It is somewhat ironic that go's big feature was AOT compilation static type checking, but it seems to immediately devolving into reflection and parsing tag key value strings to do anything. I had a typo on one of those they other day and could find the bug for an hour.

You can use alternative packages for when you need to do things more quickly. For JSON, check out fastjson, easyjson, gojay, and more.

In real code that I write, most projects never import reflect. Sometimes I import it in tests.

These are newer results[1]

golang ranks 108 and 121 in the plaintext and JSON benchmarks, which is quite abysmal.

[1] https://www.techempower.com/benchmarks/#section=test&runid=b...

The page you link to [1] shows Go at 9th for Plaintext (87.9% of the leader), 21st for JSON (96.8% of the leader). Which is still not ideal, but is a long way from abysmal.

[1] https://www.techempower.com/benchmarks/#section=test&runid=b...

Those are using "fasthttp"[1], which one should be very cautious when using[2], as it is not standard and resorts to hacks to implement.

[1] https://github.com/valyala/fasthttp

[2] https://docs.google.com/presentation/d/e/2PACX-1vTxoBN41dYFB...

Go standard library is excellent, that comment makes no sense.
Compare it to the Java standard lib: concurrent data structures, proper generic structures (tries, priority queues, etc.), GUI libraries, annotations (JPA, nullability, etc.), management, sound, etc. and you'll see what's missing.
Java's standard library is full of hot garbage.
> The lack of even a dynamic array

Are go slices not dynamic arrays? They grow automatically when necessary.

They are, but also very difficult to work with. For example, removing an element is a copy, followed by a slice notation. Inserting is combination of appends and slice notation. You don't get simple methods like insert(index,item). Also if you are growing the slice in a function, you need to find a way to return the possibly new slice variable since append might need to realloc so you often have to resort to using pointers to slices as inputs. They just aren't easy to deal with.

And you can have memory leak issues if you forget to zero a reference since the backing array still holds the reference. And none of that is efficient. A lot of temps and unnecessary copying going on.

> You don't get simple methods like insert(index,item).

This is by design, to lift the CPU and allocation costs to the foreground. You can argue that was a bad design decision, but it wasn't an oversight, as you imply in the OP.

So the AOT makes that more difficult I'm guessing? I think that go does heavy lto so shouldn't inlining at link time give the same opportunity for that?

Java's escape analysis has always been dodgy to rely on. I've had some very simple code when I couldn't for the life of me figure out why the allocations weren't being hoisted. So I don't know if gos is better or worse.

It most definitely was not an oversight, clearly intentional but I think the issues could have been solved in better ways. Better use of lto and intrinsifying some functions in slices would help a lot.

Vector operations are extremely common. Go's making them difficult to use and refusing to optimize them (lto, intrinsics, etc) just seems poor.

PS: because of the score of my top level comment I've been rate limited pretty aggressively and can't respond anymore.

I’m pretty sure Go does not do any LTO at all.
(edit: exactly what sagi said, only more long-winded) :

Removing an item from a list (that is actually performant enough that you'd want to use it) in Java is also a copy though, unless you're removing the last element. Underneath the hood, there's a copy. Same deal with insert.

Given the number of times I've seen insert or remove used where it really, really shouldn't, I'm not so sure the lack of insert/remove is a bad thing.

But yea I do get that general feeling that golang sort of... distrusts the programmer. Like the opposite of C++, where it assumes you're God, but then happily vaporizes you with God-powered-lasers.

> Given the number of times I've seen insert or remove used where it really, really shouldn't, I'm not so sure the lack of insert/remove is a bad thing.

Heavy reliance on such, as if they were free, is a very scripting-language thing. They hide all the grossness of such operations at the cost of significant memory bloat and inefficiency with simple, known-size structures (in order to make the more dynamic style run semi-fast at all).

There's no magic, and none of it's free, it just feels like it when you're push() and pop() and insert()ing all over the place. Making string manipulation closer to its roots as an array is also nice, in Go. If it's not worth bringing in a whole heavy library to deal with the awkwardness, then it wasn't worth writing the code that way to begin with. Figure out your lengths, resize as little as possible. Abuse and/or ignorance of how this all works is a big part of why we Can't Have Nice Things (performance, battery life) in the Age of Javascript.

> Making string manipulation

Heyyy another thing (and certainly I've done this myself) used incorrectly in such a way that it is extremely expensive. Specifically, concatenating log strings inside a large loop in some handler, and then not actually using those log strings because the production server didn't log down that low - but still incurring the cpu cost of the string concatenation.

I think the dynamic array in this context means an array with multiple / any types as value. Example: [1, "hello", true]
it's referring to the 'length' of the datastructure being able to change, not the types composed by the array-ish thing.
[]interface{} be like: "Am I a joke to you?"
> I find it hard to believe that Google used it much internally before releasing it

I don't work there, but I don't think it's used internally in any significant manner at all. Most development there is done in C++, Java, and Python.