You guys can keep complaining about how go is too verbose, but I love everything about go.
I love the error handling, I love the forced formatting, i love all the linting it has including style guides. When you read other source code it's so easy to understand it and make sense of it. Thank you go team
(Ok, maybe I am a bit sceptical with the latest generic additions, but overall it's a great language. I love it.)
wannabe44 4 hours ago [-]
Oh yeah totally agree. I don't understand why someone would want to write `slices.Contains(s, needle)` when you can write this beautiful poem like a Shakespeare in VSCode:
found := false
for _, v := range s {
if v == needle {
found = true
break
}
}
Oh and I totally want to build a stack trace manually. It's like doing cardio to me.
if err != nil {
return fmt.Errorf("my function name but in spaces: %w", err);
}
This is very elegant by the way, so that we need errors.Is now, which has to dynamically check if the error implements Unwrap() error or Unwrap() []error. Because having any language facilities for error handling is harmful.
bayindirh 37 minutes ago [-]
> Because having any language facilities for error handling is harmful.
No, making error handling verbose mandatory is meant to make developers do mental cardio and be mindful of what they are doing.
You can either keep developers mindful or punish them after they make a mistake by shouting at them and make them waste their time during re-compiling.
P.S.: Yes, I love Go's error handling mechanics, which makes handling errors mandatory, not optional, and if you ignore the error, this is a deliberate choice and the burden is on the developer.
Go does the former, Rust does the latter.
sapiogram 17 minutes ago [-]
What are you talking about, only Rust actually forces you to handle errors. Go functions merely return a tuple with an error along with the result, with a convention that you must checktror a non-nil error before using the result.
Rust bakes this into the type system, a function can truly return a result or an error.
bayindirh 12 minutes ago [-]
> with a convention that you must checktror a non-nil error before using the result.
So, you handle the error in the end, or forcefully and intentionally ignore it. Again, if the code goes boom, it's on the developer, not on Go.
> Rust bakes this into the type system, a function can truly return a result or an error.
Error being a variable or baked into the type system doesn't change the practical result. You must handle the error or purposefully ignore it.
> only Rust actually forces you to handle errors.
When you have two programming languages which makes you handle the error, the word only becomes a little invalid.
Semantics doesn't change the result. You have to acknowledge and act on the error either way.
b7e7d855b448 3 hours ago [-]
I don't say it's perfect, but right in this moment I feel most comfortable with go and I don't mind jumping through a few hoops or writing things multiple times
found := false
for _, v := range s {
if v == needle {
found = true
break
}
}
Do you see it? It copies the v into a local variable, which could be tremendously wasteful if it's a large struct. You should instead be taking a pointer to s[i] and comparing the value there with `needle`.
If you'd used `slices.Contains(s, needle)`, on the other hand, it could have such a performance bug in it and you'd never know.
kajman 3 hours ago [-]
> If you'd used `slices.Contains(s, needle)`, on the other hand, it could have such a performance bug in it and you'd never know.
Perhaps you're much better at programming than I am, but I prefer these semantics in a language because I figure they're much more likely to have been optimized empirically, support vectorization, and be less buggy than another rote loop I'm trying to speed through.
irq-1 55 minutes ago [-]
You're right. Just for information, slices.Contains() uses the index, not a copied value.
or contains() could be written by those who can write performant code, ..once
mathisfun123 3 hours ago [-]
> on the other hand, it could have such a performance bug in it and you'd never know.
wut...? the debate isn't between closed (incompetent) source and open (competent) source - the debate is between verbose language and expressive language.
msie 4 hours ago [-]
You forgot to put /s after your post.
Someone 3 hours ago [-]
> I love the error handling
Even if you prefer manually checking for errors after every call that might fail, I fail to see how one can love go’s verbosity. Compare go’s
foo, err := bar()
if err != nil {
return ERR;
}
with something like (hypothetical)
foo := bar() ||| return ERR;
where the compiler, seeing that bar returns an Either<int,err> can enforce the presence of the ||| clause or, alternatively, require later code to check for errors if the ||| clause isn’t present. I think that’s both more robust (prevents one from forgetting to check for errors) and shorter (allowing for showing a lot more code on a screen or page)
BobbyJo 55 minutes ago [-]
100% with you on every point. It's the only language I've worked in that lets me read other codebases without an hour or two of "wut?" happening, so they did something right!
eptcyka 3 hours ago [-]
I love how during prototyping, the compiler will tell me off for having an unused variable and fail to compile. I totally love the idea of crashing when writing on a closed channel.
spockz 1 hours ago [-]
I do love the batteries included attitude. Having benchmarking included as well as a mechanism to run tests to check (test) for race-conditions right from the language/build tool is amazing.
My only wish is that go could become less verbose. There are several frontends to go that are more compact, compile down into golang, and then let you enjoy all the benefits.
jerf 5 hours ago [-]
If generics were going to ruin the language, they would have by now. I think you can rest easy.
ncruces 4 hours ago [-]
The greatest thing about generics is … that they're not used much if at all.
Which is a great way to make sure they're not overused, which in my experience is better than underuse.
gempir 3 hours ago [-]
It doesn't have a lot of style guides or linting though. You have to install and configure quite a lot of tooling for that
jamescun 8 hours ago [-]
This isn't new?
You can see it's used by _a lot_ of linters already:
I visited that link three years ago. It isn't new. It's nifty, though.
stephbook 6 hours ago [-]
It was mentioned in the Ruff article comments and probably reposted.
jzelinskie 4 hours ago [-]
For SpiceDB[0], we've found a lot of success using this framework to define our own analyzers; it's probably 10x easier now with LLMs. No need for tribal knowledge or more time wasted on code review if you can just turn it into a linter and move on.
Can these sorts of primitives be used to create broader "architectural" linters?
fractorial 42 minutes ago [-]
Yes, and I use them often in the context of writing adversarial ‘go vet’ style anti-slop analyzers that run pre-commit.
ksec 5 hours ago [-]
So what is context? This isn't new and why the submission ?
hxtk 4 hours ago [-]
Someone in the thread about the Ruff update ingenuously said they wished Go had something like Ruff, being unaware of this framework. In that thread, someone seemed to take it as a sign that many people who might care to know about this don't yet, so they made a dedicated post for it.
hoppp 9 hours ago [-]
I was just looking for this.
Will give it a spin.
verdverm 3 hours ago [-]
The Go team's emphasis on tooling in the service of software engineering is a boon to human and agentic development alike. Give yourself and your agents great tools.
An example from one of my recent projects: https://github.com/verdverm/gmd/blob/main/Makefile (give agents simple "tool calls" instead of needing to divine the correct args/flags every time, essentially invocable agents.md content)
One of the interesting things to call out from this is using build tags for testing { unit, coverage, recorded, real api }, with the buffet allowing the agent to iterate faster and more targeted. I tend to run the linting and coverage in a new session, have a report generated, and then another fresh session to start dealing with gaps.
I love the error handling, I love the forced formatting, i love all the linting it has including style guides. When you read other source code it's so easy to understand it and make sense of it. Thank you go team
(Ok, maybe I am a bit sceptical with the latest generic additions, but overall it's a great language. I love it.)
No, making error handling verbose mandatory is meant to make developers do mental cardio and be mindful of what they are doing.
You can either keep developers mindful or punish them after they make a mistake by shouting at them and make them waste their time during re-compiling.
P.S.: Yes, I love Go's error handling mechanics, which makes handling errors mandatory, not optional, and if you ignore the error, this is a deliberate choice and the burden is on the developer. Go does the former, Rust does the latter.
Rust bakes this into the type system, a function can truly return a result or an error.
So, you handle the error in the end, or forcefully and intentionally ignore it. Again, if the code goes boom, it's on the developer, not on Go.
> Rust bakes this into the type system, a function can truly return a result or an error.
Error being a variable or baked into the type system doesn't change the practical result. You must handle the error or purposefully ignore it.
> only Rust actually forces you to handle errors.
When you have two programming languages which makes you handle the error, the word only becomes a little invalid.
Semantics doesn't change the result. You have to acknowledge and act on the error either way.
If you'd used `slices.Contains(s, needle)`, on the other hand, it could have such a performance bug in it and you'd never know.
Perhaps you're much better at programming than I am, but I prefer these semantics in a language because I figure they're much more likely to have been optimized empirically, support vectorization, and be less buggy than another rote loop I'm trying to speed through.
https://cs.opensource.google/go/go/+/refs/tags/go1.26.5:src/...
wut...? the debate isn't between closed (incompetent) source and open (competent) source - the debate is between verbose language and expressive language.
Even if you prefer manually checking for errors after every call that might fail, I fail to see how one can love go’s verbosity. Compare go’s
with something like (hypothetical) where the compiler, seeing that bar returns an Either<int,err> can enforce the presence of the ||| clause or, alternatively, require later code to check for errors if the ||| clause isn’t present. I think that’s both more robust (prevents one from forgetting to check for errors) and shorter (allowing for showing a lot more code on a screen or page)My only wish is that go could become less verbose. There are several frontends to go that are more compact, compile down into golang, and then let you enjoy all the benefits.
Which is a great way to make sure they're not overused, which in my experience is better than underuse.
You can see it's used by _a lot_ of linters already:
https://pkg.go.dev/golang.org/x/tools/go/analysis?tab=import...
[0]: https://github.com/authzed/spicedb/tree/main/tools/analyzers
An example from one of my recent projects: https://github.com/verdverm/gmd/blob/main/Makefile (give agents simple "tool calls" instead of needing to divine the correct args/flags every time, essentially invocable agents.md content)
One of the interesting things to call out from this is using build tags for testing { unit, coverage, recorded, real api }, with the buffet allowing the agent to iterate faster and more targeted. I tend to run the linting and coverage in a new session, have a report generated, and then another fresh session to start dealing with gaps.
Another super cool testing tool in the Go internal source is `testscript`. Roger Peppe extracted a number of those internal utilities here https://github.com/rogpeppe/go-internal/tree/master/testscri...