Live data from Hacker News

Go subtleties

harrisoncramer.me

111–120 of 190 posts

Re: Go subtleties

#111
post #108
post #95

Earlier quoted context omitted.

Let's assume the runtime representation case, as it's the most flexible. You'd need to do an assignability check to compare it to a typed number. Keep LHS as the interface, and RHS as the untyped constant. That means following the type pointer of LHS, switching on its underlying type (with 15 valid possibilities [1]) or similar, and then casting either RHS to LHS's type, or LHS to the untyped representation, and fina…

If it is because of overflow, the idea was that there could be size classes at compile time. A bit like sub/supertyping but for numeric types. A simple type pointer check would be sufficient.

Size classes would save some space and speed up like-to-like comparisons, but wouldn't really do much for unlike comparisons (especially vs. float or complex). Looking only at type pointers fails to account for custom types (e.g., type Foo int); remember that an untyped integer constant can be compared with these. If you want the same semantics at runtime as you get at compile time, I don't see how you can get much simpler than what I wrote, in terms of the high-level logic. Though there are undoubtedly ways to optimize it, both because Go's compiler favors speed of compilation over efficiency of generated code, and because if this were the real code, it could poke at internals while my (probably working) example has to rely on the public reflect package, which is more abstract.

Re: Go subtleties

#112
post #53

> The wg.Go Function > Go 1.25 introduced a waitgroup.Go function that lets you add Go routines to a waitgroup more easily. It takes the place of using the go keyword, [...] 99% of the time, you don't want to use sync.WaitGroup, but rather errgroup.Group. This is basically sync.WaitGroup with error handling. It also has optional context/cancellation support. See https://pkg.go.dev/golang.org/x/sync/errgroup I know it…

I never used errgroup but I realize that it's essentially the same what I end up implementing anyways.

With standard waitgroups I always move my states as a struct with something like a nested *data struct and an err property which is then pushed through the channel. But this way, my error handling is after the read instead of right at the Wait() call.

Re: Go subtleties

#113

Isn't using time.After for timeouts a bit of an anti-pattern? There is no way to cancel the pending computation.

This was fixed in Go 1.23 https://go.dev/doc/go1.23#timer-changes They will get cleaned up.

I meant that the goroutine in the example keeps running. Often this contradicts the reason for having the timeout in the first place.

Re: Go subtleties

#114
post #93

FTA: “In Go, empty structs occupy zero bytes. The Go runtime handles all zero-sized allocations, including empty structs, by returning a single, special memory address that takes up no space. This is why they’re commonly used to signal on channels when you don’t actually have to send any data. Compare this to booleans, which still must occupy some space.” I would expect the compiler to ensure that all references to t…

Go is copy by default.

That means it would work if *bool is possible but it's not.

Re: Go subtleties

#115

I balked a little when the article refers to format strings as "string interpolation" but there's multiple comments here running with it. Am I out of date and we just call that string interpolation these days? I also found this very confusing: > When updating a map inside of a loop there’s no guarantee that the update will be made during that iteration. The only guarantee is that by the time the loop finishes, the ma…

"Am I out of date and we just call that string interpolation these days?"

It's all just spelling. Your compiler just turns

    x = "I want ${number/12|round} dozen eggs, ${name|namecase}"
into

    x = StrCon("I want ", round(number/12), " dozen eggs, ", namecase(name))
anyhow. It's not a huge transform.

I think people get bizarrely hung up on the tiny details of this between languages... but then, I think that extensive use of string interpolation is generally a code smell at best anyhow, so I'm probably off the beaten path in more than one way here.

Re: Go subtleties

#116
post #6
post #5

Great list of why one can love and hate Go. I really did enjoy writing it but you never get the sense that you can be truly certain your code is robust because of subtle behaviour around nil.

I guess as a corollary, Go really rewards writing the dumbest code possible. No advanced type shenanigans, no overuse of interfaces, no complex composition of types. Then you will end up with a very fast, resource light system that just runs forever.

Oh boi, all my RW mutexes for maps across goroutines would disagree.

Re: Go subtleties

#117
post #110

Earlier quoted context omitted.

I don't know why every time people complain about this there is an assumption that we just don't understand why it is the way it is. I get that x can implement X and x can have methods that work with nil. I sometimes write methods that work with nils. It's a neat feature. What's frustrating is that 99.99% of written go code doesn't work this way and so people _do_ shoot themselves in the foot all the time, and so at…

Because in the last dozen times I've handled this question the root cause is lack of understanding of why. Inductively it is logical to conclude that's the reason next time. It is probably also the case the bulk of readers of this conversation are still in the camp that don't understand the problem correctly. If you understand that there isn't really a fix and just wish there was one anyhow, while I still disagree in…

I can't think of good way to give programmers control over boxing without adding a bunch of complexity that nobody wants.. but it doesn't seem out of the realm of possibility that the linter could detect issues like this. It should be able to spot methods that aren't nil-safe and spot nil values of those types ending up in interfaces with those methods. Then you'd have less explaining to do!

Re: Go subtleties

#118
post #56
post #53

> The wg.Go Function > Go 1.25 introduced a waitgroup.Go function that lets you add Go routines to a waitgroup more easily. It takes the place of using the go keyword, [...] 99% of the time, you don't want to use sync.WaitGroup, but rather errgroup.Group. This is basically sync.WaitGroup with error handling. It also has optional context/cancellation support. See https://pkg.go.dev/golang.org/x/sync/errgroup I know it…

I thought exactly the same thing. I use errgroup in practically every Go project because it does something you'd most likely do by hand otherwise, and it does it cleaner. I discovered it after I had already written my own utility to do exactly the same thing, and the code was almost line for line the same, which was pretty funny. But it was a great opportunity to delete some code from the repo without having to refac…

> and the code was almost line for line the same, which was pretty funny.

One of the core strengths of Go is that it fits the zen of Python's " There should be one-- and preferably only one --obvious way to do it" and it does this very nicely.

Re: Go subtleties

#119
post #6

Earlier quoted context omitted.

I guess as a corollary, Go really rewards writing the dumbest code possible. No advanced type shenanigans, no overuse of interfaces, no complex composition of types. Then you will end up with a very fast, resource light system that just runs forever.

And code with zero ability to do fancy trickery ("expressive" as some people like to say) is easy to read even if the codebase - or even the language - is unfamiliar. Which is really handy when shit's on fire and you need to find the error yesterday. You can just follow what happens instead of trying to figure out the cool tricks the original programmer put in with their super-expressive language. Yes, the bug is on…

> And code with zero ability to do fancy trickery ("expressive" as some people like to say) is easy to read even if the codebase - or even the language - is unfamiliar.

A mate of mine did Comp Sci back in uni when First Years were taught Turbo Pascal showed me some, when I was still doing stuff in ZX Spectrum BASIC and Z80 assembler in high school. It was immediately clear what was going on, even if the syntax was a bit unfamiliar.

By contrast I've had to sit and pick apart things with strings and strings of ternary operators in the same expression, as part of case structures that relied on fallthrough, because someone wanted to show how clever they were.

My Pascal-using mate called stuff like that "Yngwie Malmsteen Programming". It's a phrase that's stuck with me, over 30 years later.

Don't do that "WEEDLYWEEDLYWEEDLY" shit. You're just showing off.

Re: Go subtleties

#120
post #93

FTA: “In Go, empty structs occupy zero bytes. The Go runtime handles all zero-sized allocations, including empty structs, by returning a single, special memory address that takes up no space. This is why they’re commonly used to signal on channels when you don’t actually have to send any data. Compare this to booleans, which still must occupy some space.” I would expect the compiler to ensure that all references to t…

Go is copy by default. That means it would work if *bool is possible but it's not.

If they did it without you explicitly making bool a pointer, then it would be syntactic sugar and it would kind of fall away from the spirit of Go which is, if you look at a file everything that's happening is known to you, there's no metaprogramming witchcraft anywhere in sight usually.
Post reply on HN