Live data from Hacker News

Notes on the Go translation of Reposurgeon (2020)

gitlab.com

71–80 of 155 posts

Re: Notes on the Go translation of Reposurgeon (2020)

#71
post #39

It's not surprising that the code base grew when reimplemented in golang. It would have probably been even shorter had it been rewritten in Python itself. Just the other day, I was able to condense over 15 lines of golang code into 3 lines (could also have been 2 lines) in a Python-like syntax, both reducing code length, and substantially increasing readability as it would make the underlying logic clearly stand out…

I think you have to be very careful before claiming readability gains from fewer lines of code. I've done a lot of Python programming and for simple things like mapping a single function over a list, a list comprehension or generator expression can indeed be a tiny bit more readable than a for loop, but combining that with some filtering or flattening and colleagues (and my future self) get frustrated. I've seen the…

> There's some temptation to think that terse==readable, but in practice this rarely extends beyond the simplest cases

A quick glance at any array language (APL, J, K, Q, etc.) confirms this. ;)

Re: Notes on the Go translation of Reposurgeon (2020)

#72

Earlier quoted context omitted.

I think you have to be very careful before claiming readability gains from fewer lines of code. I've done a lot of Python programming and for simple things like mapping a single function over a list, a list comprehension or generator expression can indeed be a tiny bit more readable than a for loop, but combining that with some filtering or flattening and colleagues (and my future self) get frustrated. I've seen the…

I didn't yet get around to writing Go in any significant capacity (it's not in an interesting spot for me) but I've had to read some and to me it seems like about half of all Go code does approximately nothing. It seems really weird to me that Go doesn't have a Result/Optional type (or sum types in general) and instead prefers multiple return values instead, and consequentially does not have error-handling operators…

One of the issues I had with Go was that even though functions can return pseudo-tuples (multiple return values), there are no tuples anywhere else in the language. So you can't chain functions which return (T, err), easily create a slice of their return values, feed their output to a channel, etc. Just made handling operations on slices so tedious

Re: Notes on the Go translation of Reposurgeon (2020)

#73

   What I really missed was generic map-function-over-slice, which could be
   handled by adding a much narrower feature.
   
   If one graded possible Go point extensions by a figure of merit in which the
   numerator is "how much Python expressiveness this keeps" and the
   denominator is "how simple and self-contained the Go feature would be",
   I think this one would be top of list.
   
   So: map as a functional builtin takes two arguments, one x = []T and a
   second f = func(T)T. The expression map(x, f) yields a new slice in
   which for each element of x, f(x) is appended.
I think this is an excellent way of evaluating new features, and it represents a real missed opportunity for Go to explore new PL territory. Instead, we're getting full-blown user-defined generics, which increases the "denominator" far, far more than it increases the "numerator."

Re: Notes on the Go translation of Reposurgeon (2020)

#74
post #70

Earlier quoted context omitted.

I think you have to be very careful before claiming readability gains from fewer lines of code. I've done a lot of Python programming and for simple things like mapping a single function over a list, a list comprehension or generator expression can indeed be a tiny bit more readable than a for loop, but combining that with some filtering or flattening and colleagues (and my future self) get frustrated. I've seen the…

I didn't claim that terse is always more readable. It was in the example I gave, and practically every golang program could be written in a more terse, more readable, and less error prone way in Python/Java/C#/etc.

I understand that you didn’t claim this explicitly, but it’s a common misconception so I addressed it anyway. While I have no doubt that a given Go program could be written more tersely in Python, Java, or C# I’ve written and operated enough programs in those languages to know that the results are rarely if ever more readable or less error-prone. I think Go’s preferences for simplicity over cleverness and explicitness over terseness are significant factors in these readability and quality disparities. Newline characters aren’t where your bugs are coming from.

Re: Notes on the Go translation of Reposurgeon (2020)

#75
post #46

Earlier quoted context omitted.

I’m not sure that’s a great example. mmap(2) is a swiss army knife of a function. There are many crates that build all kinds of things on top of mmap, and they’re not all interchangeable. Allocators, file io, gpio, actual virtual memory mappings. My view is that when you develop a product, you have to own everything. The users don’t care if the bug comes from code you wrote, or code in a library, or the language’s st…

>My view is that when you develop a product, you have to own everything. The users don’t care if the bug comes from code you wrote, or code in a library, or the language’s standard library, or the OS. You have to fix the bug no matter what caused it. It doesn’t matter if the code came from a vendor or a language designer or stack overflow; you are the one responsible for fixing it if something goes wrong. So then usi…

Sometimes. Using someone else’s code is only a benefit if it saves time overall, compared to writing it yourself. You have to count both the time to write it and the time to maintain it over however long your product is active. You have to assume that you’ll be maintaining it yourself either way.

Also, don’t forget that languages with big standard libraries, like Python or C# or Java, always end up with oodles of stuff in there that is deprecated or incompatible. That’s as bad a sign as anything.

But I do agree with you, a lot of the time you have inherited the mess rather than writing it yourself. Not much you can do about it, except to clean it up and then dodge better next time. Going back to Rust specifically, Cargo gives you some tools that make the mess easier to clean. The Rust language also helps, because you can safely use multiple versions of your dependencies, when it turns out to be necessary.

Re: Notes on the Go translation of Reposurgeon (2020)

#76

One thing that the people saying "just use a struct for keyword arguments" are missing is that structs should signal intent, i.e. "this is a concrete concept in the system." A Repository, Commit, Message, Person, etc. struct are all concepts in the domain, whereas "the arguments for this particular function" is not. I think Go people are allergic to writing code that does anything other than functionally work.

> structs should signal intent

Isn't a collection of parameters to a function an intent?

Re: Notes on the Go translation of Reposurgeon (2020)

#77

Great writeup. Some of the points are moot now that generics are being released, but some very valid concerns. I would also add that Enums + Exhaustive Switch is a very very weak area in Go that would really benefit the language a ton. I've used those features in other languages and that's one of the things I miss the most, especially when dealing with a ton of web API's that have a defined set of values for properti…

> Able to have the confidence that we're checking for every situation that could occur on an enum type across the codebase is one less thing I need to worry about. golangci-lint ( https://github.com/golangci/golangci-lint ) is an absolute must, and includes https://github.com/nishanths/exhaustive which will check this for you.

Configurable linters are usually best avoided, because it's too easy to remove a check rather than fix your code, in a crunch.

Re: Notes on the Go translation of Reposurgeon (2020)

#78
post #25

Earlier quoted context omitted.

Honestly, you don't notice it once you get into the Go mindset. The exception handling looks onerous, and is a pain at the start. But it doesn't take long to get used to it, and then (for me anyway) it becomes second-nature. Everything returns an error, and you have to handle that error (even if only passing it up again). Static typing is more "fun" when you're exploring new concepts, but interfaces are the key. Defi…

Not noticing it is exactly my fear. Passing an error manually up several levels when it may only be a theoretical concern is a ton of expressive duplication. If I'm in the mindset, that would feel like valuable work, even though it isn't actually making things better for users. It reminds me of one team I dealt with years ago. They were Java experts used to doing enterprise stuff; their overlords had put them on a sc…

What you call "expressive duplication" I call "explicit intent". The error control flow is not subordinate to the happy path.

Re: Notes on the Go translation of Reposurgeon (2020)

#79
post #23

Earlier quoted context omitted.

Honestly, you don't notice it once you get into the Go mindset. The exception handling looks onerous, and is a pain at the start. But it doesn't take long to get used to it, and then (for me anyway) it becomes second-nature. Everything returns an error, and you have to handle that error (even if only passing it up again). Static typing is more "fun" when you're exploring new concepts, but interfaces are the key. Defi…

> But it doesn't take long to get used to it I did get used to it, but all the if err != nil { return nil, err } sometimes taking up half or more of the vertical space of a function is still an eyesore to me, even after writing a quite substantial amount of Go.

Error handling being explicit isn't an eyesore. It lifts what is with exceptions a hidden control flow to the foreground.

Re: Notes on the Go translation of Reposurgeon (2020)

#80

What I really missed was generic map-function-over-slice, which could be handled by adding a much narrower feature. If one graded possible Go point extensions by a figure of merit in which the numerator is "how much Python expressiveness this keeps" and the denominator is "how simple and self-contained the Go feature would be", I think this one would be top of list. So: map as a functional builtin takes two arguments…

I also came from Python (15 years of experience) to Go and I think newcomers to Go index too hard on terseness. The for-loop equivalent for a map over a list is more characters, but it's really straightforward and easily recognizable in the code. In the general case, I'm glad that Go doesn't try to explore new PL territory, optimizing instead for things that are known to improve developer productivity. None of this is to say that Go has no room for improvement--only that "terseness" is not high on the list of improvements I'd like to see (for example, I'd rather have sum types with exhaustive pattern matching).
Post reply on HN