Live data from Hacker News

Python Is Easy. Go Is Simple. Simple != Easy

preslav.me

211–220 of 313 posts

Re: Python Is Easy. Go Is Simple. Simple != Easy

#211
post #203

Earlier quoted context omitted.

My experience translating a codebase from Python to Golang (chat application), is that 20k of Python really does translate to around 40k of Golang to get the same functionality. And it’s not just due to language but also expressiveness of the library ecosystem.

I don't have any concrete measurements, but I think this is about right, ± a bit depending on the type of application. I don't think this is necessarily a bad thing though; Go is a bit more explicit on a number of things and there's less opportunity to make code 'dense'. Both have their own up- and downsides.

I really think go goes too far to the point of hurting productivity and expressiveness. For example, go is missing any way to write parametric enums (sum types). Sum types make code much simpler and more expressive. The equivalent go code (using interfaces) is uglier, more verbose and more error prone. There’s a lot of features like that which go leaves out - like iterators, optional (nullable) types and so on.

The only tradeoff I see is that go is faster to learn, because it has less syntax. But at the end of the day I don’t mind spending a bit more time learning a language if the result is I can write more expressive and clear code. I love go’s concurrency model. It’s clever and simple to learn. I wish they applied the same pragmatism when designing other parts of the language.

Re: Python Is Easy. Go Is Simple. Simple != Easy

#212
post #8

Earlier quoted context omitted.

Huh? Having defer statements and error returns vs. dealing with exceptions gives Go the win all by itself. And then there is the business of being able to make a type automagically satisfy an interface. (Java may have fixed some of the agony of creating classes just to satisfy a required interface. Last I used Java, it didn't have delegates and whatnot.)

Go's defer is verbose and unwieldy compared to Python's `with` statement or Rust's lifetime system. In Python, you don't have to manually write any code to close the file, you just do: with open('foo') as f: ... And the file will be closed after that block of code finishes executing. Similarly in Rust if you do "let file = File::open("foo")?;", when the variable drops the file will be closed. If you want to loop over…

I wish defer was block-scoped rather than function-scoped; that would solve the "defer in a loop" problem. Right now I just wrap the lot in a function for that, which works and isn't too bad, but meh.

defer is more flexibly and explicit though; I rather like that. It's pretty unclear what exactly that "with" does, what you can and can't use inside "with", you can't "just" run any arbitrary code without creating your own class, and you sometimes end up with 3 or more levels of nested "with"s that could have been one defer.

In short, I don't think there's a clear winner. Both are clunky in some scenarios where the other is easier.

Re: Python Is Easy. Go Is Simple. Simple != Easy

#213
post #65

Earlier quoted context omitted.

> I need to make a change across both of these modules. Will my compilation pick up the changes? Yes, add a replace directive to A's go.mod and point it to B's directory. It'll pick up changes immediately. You can also vendor + disable modules + change stuff in the vendor folder to quickly experiment, though IDEs tend to get moody about this. Backwards incompatible in principle: release a new major version of B. Impo…

> Yes, add a replace directive to A's go.mod and point it to B's directory. It'll pick up changes immediately. Nowadays you just create a go.work file. That's much less cumbersome than 'replace' directives. If a module is in the go.work it isn't downloaded from a remote git repo, but overshadowed by your local files.

Ehhh... I find it far more similar than not in terms of effort/maintenance, and much less likely to work with [random tool X] tbh. Replaces work with basically everything, and you can vendor when they don't - workspaces have no vendor equivalent AFAIK.

go.work is also rough to use with existing folders / a gopath-like setup, because they're super awkward if you don't have a dedicated folder with dedicated clones with just the stuff you're using in the workspace (which has some nice benefits, but most people are not even aware you can do that afaict, GOPATH caused so much pain that there's now mental scar tissue that'll take a while to clear). Replaces work fine with that if you open two editor instances, workspaces generally index everything or nothing and get confused.

Tooling support has likely improved since I last tried it (around 1.19?), and I 100% agree that it's a viable option worth considering (thanks for the comment!), but I'm not sold on them yet. Better for some things, worse for others.

Re: Python Is Easy. Go Is Simple. Simple != Easy

#215
post #197

Python is valuable due to the ecosystem of libraries it offers. The language itself is extremely poor. I think this is not something most Python users are aware of since if you are doing ML, data-science or simple scripting there is little reason to step outside of the ecosystem. - Weird scoping rules - Very limited list-comprehensions - Ability to monkey patch things is a liability - Mutability by default - Lack of…

I could address each of these "issues" but I'd rather focus on the following: > The language itself is extremely poor > I think this is not something most Python users are aware of These two statements are contradictory. If it was indeed so "poor", people would notice :) If they instead increasingly adopt it (out of appreciation, not because they are lobbied into doing it) it becomes really difficult to logically dem…

You could claim the same thing about JavaScript. It's very possibly more popular than Python, but it's definitely not better designed than Python or most of the other languages in current use.

Re: Python Is Easy. Go Is Simple. Simple != Easy

#216
post #153

Earlier quoted context omitted.

Java boilerplate is way worse AND hidden behind annotations and so many level of abstractions!

That's mostly a facet of frameworks like Spring, not something inherent to Java itself.

There’s a strong culture in the Java community which actively encourages this style of programming. I agree - I don’t think it’s an inherent part of the Java programming language. At least not any more - recent versions of Java have a lot of nice features! But you still see a lot of this overly abstracted, “enterprise” Java code in the wild all over the place. I find it easier to just specialise in other languages.

Re: Python Is Easy. Go Is Simple. Simple != Easy

#217
post #203

Earlier quoted context omitted.

I don't have any concrete measurements, but I think this is about right, ± a bit depending on the type of application. I don't think this is necessarily a bad thing though; Go is a bit more explicit on a number of things and there's less opportunity to make code 'dense'. Both have their own up- and downsides.

I really think go goes too far to the point of hurting productivity and expressiveness. For example, go is missing any way to write parametric enums (sum types). Sum types make code much simpler and more expressive. The equivalent go code (using interfaces) is uglier, more verbose and more error prone. There’s a lot of features like that which go leaves out - like iterators, optional (nullable) types and so on. The o…

All these things are a trade-off; unqualified statements that "sum types make everything simpler" are just wrong, because they don't. Whether it's worth the trade-off is a subjective judgement call and a completely different thing.

Re: Python Is Easy. Go Is Simple. Simple != Easy

#218

Yeah, but the amount of boilerplate one must read and write in Go is frustrating, even compared to Java.

You can see the structure in the boilerplate pretty quickly. And because it's boilerplate, you'll also instantly see when it's missing.

Sounds like a waste of time. I’d rather just not have that code in the first place. I don’t want to write it. I don’t want to maintain it. I don’t want to have to scroll past it when I’m working, and have my monitor made artificially smaller because my code has the same repeated error handling code everywhere. What a waste of brain cells.

Re: Python Is Easy. Go Is Simple. Simple != Easy

#219

Am I insane that: > filtered_temps = { entry["city"]: entry["temp"] for entry in temperatures if entry["temp"] > 20 } is less readable to me than: > for _, ct := range temperatures { if ct.Temp > 20 { filteredTemps[ct.City] = ct.Temp } } ??

And all of it is less readable than city_temps .select { |ct| ct.temp > 20 } .to_h { |ct| [ct.name, ct.temp] } Or let map: HashMap = city_temps .iter() .filter(|ct| ct.temp > 20 ) .map(|ct| (ct.name, ct.temp) ) .collect();

There is no need to use anything but filter, like

   filtered_temps = list(filter(lambda e: e["temp"] > 20, temperatures))
IMHO the most readable version (and coincidentally also the shortest).

Re: Python Is Easy. Go Is Simple. Simple != Easy

#220

Earlier quoted context omitted.

Check out ErrCheck. It's a static analysis tool that detects exactly this. We added it to our common Makefile that we use for testing/building Go projects. Typically I have it test for this among other things before I commit, and then it runs again in CI scripts before a merge to main is allowed. In my experience, if you're not checking errors, then you're often just going to crash loudly. Likely at a similar point t…

The problem with error checking is that Go doesn't cover every case BY FAR. EVERY memory allocation can fail. And I mean EVERY. var x := 5 // where's the error handling? EVERY kernel call can fail. Even this is still not a 100% correct way to call fmt.Printf("Hello, World!"): s := "Hello, World!") writtenSoFar := 0 while writtenSoFar If you don't do this, you will find, for example, that writing large amounts of data…

In practice, how often does your rant on memory safety really apply though? Because I currently feel that you're inflating the argument substantially to make it seem like a much bigger, much more common problem, than it is. For reference, in 5-6 years of Go programming, memory allocation has been a problem for me exactly one time, and it was because I was a noob and tried to push about 60GB of data into a variable at once on a virtual machine with 32GB of memory available to it. And it wasn't a silent error, the systemd service I wrote for the application was crashing each time it attempted to load up that mega-variable until I rewrote it in a sane way.
Post reply on HN