Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

You could think of the Go dev team's last ten years as trying to find the right balance between features (asked for by the expert devs that use Go) and simplicity (a value that the designers hold, but that most expert devs making feature requests don't care about). Generics always felt to me like this dynamic in a nutshell. Lots of good reasons to prefer generics when you need them, and it feels like a nearly ecosystem-killing amount of complexity to implement a type system like Rust on top of Go - there's literally almost no reason to use Go in that case.

Anyway, I like seeing this slight reversion in favor of simplicity, I think it's the right call for where Go's targeted: being a better Java for teams of mid-tier engineers.



It's interesting how simplicity so often gets mistaken for a lack of sophistication. Designing a language for clarity and maintainability is a laudable goal, and so is choosing to use one. Chasing complexity, or reaching for the latest trendy language that lets you "express yourself" in ten different ways to do the same thing, isn't what makes someone an S-tier engineer. Simplicity isn't a concession. It's a hard discipline.


> Designing a language for clarity and maintainability is a laudable goal, and so is choosing to use one. Chasing complexity, or reaching for the latest trendy language that lets you "express yourself" in ten different ways to do the same thing, isn't what makes someone an S-tier engineer.

But it sure looks good on your resume!


In exactly the same way, complexity you don't understand the purpose of is often disregarded as complexity for complexities sake.

It's easy to get things simple and wrong, and hard to get things simple and right. And sometimes complexity is there for a good reason, but if you don't work hard to understand, you'll fall into the "simple and wrong" camp often.


One problem with simplicity is that it often moves the complexity elsewhere, particularly if you're designing things that others use.

Brainfuck the language is simple to use and implement. It has only 8 commands. Brainfuck programs are virtually unreadable, unless you can get your head around it.

The advantage of trying to solve complexity is that if you can solve it, you've solved it once and exactly once for everyone involved.


But each line of Brainfuck is very simple and easy to understand! - is the type of argument that I often here from folks that like Golang...


Thing is, it's not even necessarily true for Go. E.g. that whole `iota` thing is hardly a good example of "simple and obvious" language design compared to enums in... just about everything else. Or we could talk about the difference between a nil interface value vs interface value wrapping nil.


Go being simple and fast to compile, doesn't mean go is simple to use.

My friend tells me the primary use case for go are microservices no more than one page worth of code deployed in kubernetes.

I think that's correct. Anything larger is just masochism.

There will be a revolt at some point, the question will be to what? Rust? Probably not. Maybe a C++ resurgence...


FWIW, the revolt to Rust is already happening.

Why would anybody choose C++ over Rust in 2025? The biggest (valid) criticisms against Rust are that it is difficult to learn and use, but C++ is like 1000 times harder. When people say Rust is complicated they’re comparing it to modern GCed languages, not to C++.


Why C++ still gets chosen:

1. There is a lot more experienced C++ devs around.

2. There are a lot more libraries that are readily usable from C++ but would need to be wrapped to use in Rust.

3. The tooling (IDEs etc) around C++ is more mature.


> E.g. that whole `iota` thing is hardly a good example of "simple and obvious" language design compared to enums in... just about everything else.

I actually disagree with this specific take. I do agree that iota is an unnecessary bit of cleverness (especially with that name) but I’d much rather a langage have nothing than the pile of lies and garbage that are C enums. At least then it’s not pretending.


Maybe a decade ago I saw a video of Rob Pike telling people they can abandon C++ because golang was good enough. He proclaimed that people can toss out their reams of C++ code and replace it with Go. That never really came to fruition -- even as bad as C++ is.

The only godsend of C is that code written in the 1970's can still be compiled today -- half a century later. You can write code in your 20's in C and still be assured it will still work a half century later in your 70s. (as long as you don't use system libraries which might change.... etc.)

A lot of people complain about Rust compile times. But honestly, I'd rather work in a language that is trying to solve complexity rather than push it off on to the user.


Mostly because he doesn't get why some of us reach out for C++, despite its warts.

As I wrote at the time on Lambda The Ultimate back in 2012,

http://lambda-the-ultimate.org/node/4554#comment-71504


As much as I hate Go, I have to admit that it does sort of fill a niche, or at least it did at the time it was released. If you wanted something less baroque and complex than C++, but still care about performance enough to not want to use an interpreted language, and don’t want to use Java because it’s overly verbose and attracts OOP architecture astronauts, there wasn’t much choice other than Go when it came out.

There’s a very high probability that something like Cockroach would use C++ if Go had never existed, so Rob Pike was sort of right, if you squint. On the other hand, if Cockroach were started today it would probably be written in Rust.


I think you’re missing a couple key benefits to go: compile time and cross arch builds. The story here is best in class by far. It’s so so simple and fast to compile go for 10 architectures and distribute a binary.


Then tell them to write all their code in Brainfuck if it's that easy.

In fact, tell them to write a brainfuck transpiler in brainfuck to transpile go lang to brainfuck to make it easier for you communicate with their native tongue directly.

https://stackoverflow.com/questions/16836860/how-does-the-br...

But honestly if you're a professional programmer, you should constantly be asking yourself how do I reduce complexity for others first, not myself. And that's where golang gets it wrong. Golang asks very specifically first and foremost how do they get their compiler right -- even if it comes at the potential expense of the users.

I mean golang is not brainfuck by any margin, and it is reasonable for what it tries to do. But, in my experience, if you're writing code longer than a page, golang is probably the wrong language.


A core conflict is determining who should hold complexity ("how much" is implied). From an operating systems perspective, I like seL4's approach of being a highly minimal kernel, which necessarily means pushing out significant complexity to userspace to handle. I want to go even further in that direction. Despite the massive complexity spike, kernel minimality has significant benefits for increasing userspace programs' power. I think programming languages are somewhat different. Both operating systems and programming languages are deeply foundational notions of abstraction, and even mesh: Smalltalk[0] or Forth being said to include an operating system isn't outrageous. An operating system exposes languages (e.g. shell commands, syscalls, libraries, services) and a programming language undergirds a system. My suspicion is that it's because an operating system is built up, whereas a programming language is the tool in hand. They're at such different levels of construction that they aren't comparable. I have a refinement, which also ties in something I sneakily avoided earlier: programming languages are like kernels, especially microkernels like seL4. Bundling the whole OS is cheating; the job is already done. But I think there's still a difference. When a kernel is built, the OS isn't far behind; a purpose is set. When a programming language is built, it's made (usually) for generality. The exceptions to this (domain-specific languages) prove my point: they have a purpose in mind. The complexity is still there, but building an operating system seems to provoke long-lasting further abstractions (services, components, libraries) whereas programming is more fragmented in its abstractions (frameworks, libraries, language features). Put another way: operating system developers seek simplicity of the whole system, since that is there scope. It's harder to define a system for programming languages, although it is there (the sum of programs produced), and so optimizations are more local at the expense of global progress.

[0] https://dl.acm.org/doi/pdf/10.1145/2525528.2525534


The problem is further exacerbated by needless complexity being seen as sophistication, and in the end; one's competency level. A lot of today's bloat and bullshit is caused by this attitude. Like a football team full of body builders preoccupied with showing of their muscles and wondering why they're languishing at the bottom of the table.


> there's literally almost no reason to use Go in that case.

I work in C# and C++ day to day now, and in $PREV_JOB I used Go and C++. my go builds on a similar size project were quicker than the linter in my C# project is right now. Go's killer feature IMO is that it's _almost_ scripting level iteration speed.


I too like this feature of go quite a lot. But I think it's supercharged by the major reason I'd pick go for a mid-size team; the language is exceedingly easy to parse, code in and understand even if you're not a genius. I think the testing support and very moderate type support hit a valuable place in development ecosystems -- as you say, you get near instant linting feedback about a lot, and it's also pretty easy to read and write in.

Basically, the mental model required for coding in go is low load. That's a great feature.


> as you say, you get near instant linting feedback about a lot

Sorry, it wasn't clear. I could run `go build && ./myapp` and have my application running quicker than `dotnet format` finishes. Linting in .net is slower than compiling in go.

Agree on everything else. It has it's share of footguns, for sure, but so does every language.


FWIW dotnet format is not a linter, it's just a formatter and yes it is slow (I guess because it's ever so slightly neglected, I'd expect most developers use IDE-provided or Roslyn-provided (for VSC) auto-format instead).

Overall, the tooling could be faster but because it is JIT-based and performs heavy unbound reflection, it's not very amenable to the NAOT compilation in its current form if you are used to frequently running 'dotnet build' and 'dotnet run' where startup latency imposed by JIT is most noticeable. Also keep in mind that both invoke the full build-system. It's closer to what Cargo does than what Go tooling does. Are you using .NET 9 SDK? Another feature I suggest looking at is hot-reload with 'dotnet watch'. It can shorten iteration cycles for doing the back-end work substantially.


Honestly I don’t care why it’s slow. It’s up to dotnet to sell itself. It’s not my problem if dotnet invokes the full toolchain to run an incremental tool - my point is that go’s entire compilation is still quicker and that’s a huge boon.


The tooling itself is not _slow_ (are you intentionally misreading this?). It is slow_er. Why are you using dotnet format? Try CSharpier instead.

It does not matter on CI, it matters locally where you should be using something else.

And of course if you are looking for an excuse to use Go (which is a worse language), fixing this or any other "issue" will not help - there will always be another reason.


Do real organizations actually use C#? Every time we've evaluated it we concluded it's a worse, MS-flavor Java rewrite so we didn't take it too seriously. Does it have any actual advantages over Java?


Lots of real orgs use C#.

StackOverflow survey (self reported) for 2024 shows it at #5 leaving out HTML/CSS, and SQL[0]

DevJobsScanner shows it at #4 via scraping job postings[1]

It definitely has heavy adoption; well above Rust and Go despite what we see here on HN.

    > Does it have any actual advantages over Java?
The language evolves faster and is more akin to Kotlin than to Java, IMO. The DX is fantastic and there are a few gems like LINQ, Entity Framework, and Roslyn source generators. Modern C# can be very dense yet still highly legible.

C# switch expressions with pattern matching (not switch-case), for example[2], are fantastic.

[0] https://survey.stackoverflow.co/2024/technology

[1] https://www.devjobsscanner.com/blog/top-8-most-demanded-prog...

[2] https://timdeschryver.dev/blog/pattern-matching-examples-in-...


It has been 8 years since I last wrote any C# code and I still miss LINQ to Objects. It felt so natural building up queries against collections and very readable.


They've made the language much more terse, IMO, taking a lot of cues from TypeScript/JS as well as other languages. Constructs like primary constructors, record types, pattern matching, and destructuring continue to improve ergonomics, IMO.

For a quick comparison, check out https://typescript-is-like-csharp.chrlschn.dev/


You are overestimating the voices / anecdotes / evangelists from the internet. I did this as well ... so no offense. When reading HN or Reddit one can easily get the impression that Java, C++ and C# are dead and the world has turned to Rust and Go. Esp. C# is underrated in the real world.

Here's some data of 12M scraped job offerings:

https://www.devjobsscanner.com/blog/top-8-most-demanded-prog...

JavaScript: 31.42%

Python: 19.68%

Java: 18.51%

C#: 11.90%

C/C++: 8.29%

Go: 2.38%

Rust: 0.39%

I was a bit shocked about the Rust numbers. I'd expected it to be slightly above Go. Anyway. C# is strong. Java even more.


> I'd expected it to be slightly above Go.

Why's that?

Go was designed explicitly to serve the particular needs of a particular area of software development that allegedly sees more than average development activity. In fact, its designers have expressed some surprise that people found it useful in other areas of programming. Rust, on the other hand, tries to be much more general purpose. Being a jack of all trades master of none, so to speak, is a great technical quality, but without particular focus it is much harder to get the numbers up.

It is quite similar to why Javascript blows all of the other languages out of the water. It would be surprising if Rust had more usage like it would be surprising if C had more usage than Javascript.


A lot of Rust jobs aren't "Rust jobs," that is, they don't have "Rust" in the description.

Also, "job openings" is not the same as jobs, my organization isn't currently hiring engineering roles, yet we employ ~60 engineers, of whom most write Rust. And we're just a tiny startup.


When I was at EA, almost all of the internal tools for building and editing games were written in C#.


It is quite widely deployed in many non-software companies of all sizes that build custom software to run their business, and really seems to dominate in small and medium businesses.

Its also popular in Game dev mostly due to Unity, but you have other good options to use C# in game dev as well. I can't think of another kind of software company that uses it a lot other than ones that integrate deeply into the microsoft stack.

As a language, it was far, far ahead of Java for many years (the long dark tea-time of Java 7).


It is IMO better than Java these days, although they're pretty close. Whenever I have to go back to Java I find odd things missing, like unsigned long.

AOT is pretty good when it works.


> Do real organizations actually use C#?

Sure. For me the best thing about dotnet is that you most likely find an official solution to most "basic" things needed to develop microservices (I intentionally call these basic because you don't want to worry about lots of things at this level). Go on the other hand excels at cross-cut and platform development.


C# is easily my favorite language and Java is one of my least favorite languages.


>> Does it have any actual advantages over Java?

Probably not. Why learn C# if you already know Java? Similarly, why learn Java if you already know C#?


Java lacks huge low-level feature set C# comes with.

It is also generally less nice to work with - Maven and Gradle are a way bigger PITA than .NET CLI (which is similar to Cargo and Go CLI), NuGet and MSBuild. Base C# syntax lends itself to more streamlined expression of business logic (e.g. with pattern matching, tuples, records and their deconstruction).

In Java, there are odd issues and resulting method gymnastics caused by generics with type erasure, and many of its base containers don't unify nicely as the ones in C# do to IEnumerable<T> or Span<T>.

Writing highly concurrent + parallelized code is way more cumbersome (and generally less efficient) with the current rendition of virtual threads, completable futures or even upcoming structured concurrency API than doing so with .NET 'Task<T>'s and their composition.

ASP.NET Core is much faster and more focused than Spring Boot. EF Core is way more powerful and significantly terser to use than Hibernate, JPA or, to an extent, JOOQ.

You can also relatively easily ship fully self-contained and relatively compact (with trimming) applications, often as a single file. With additional effort, NativeAOT provides native compilation and smaller-than-Go binaries while having much wider support across ecosystem than GraalVM Native Image within JVM space (e.g. it's one command away to get a gRPC-based ASP.NET Core microservice template which compiles to fully native binary, it also does not use any special tricks - just regular code).

They are very much not 1:1 languages. Depending on the domain, there may very large differences in developer productivity, level of comfort and effort required to achieve a competitive implementation.

Java strengths lie in its comparatively larger and more diverse ecosystem in enterprise space alongside certain high-profile projects, predominantly by Apache foundation. On technical merits it does have less to offer.

The main technical exception - Java has superior GC implementation(s).

I'd say if your goal to expand your horizons, then it's more important to pick a problem that can't be nicely solved with Java. In that case, C# will offer more pleasant and moderately familiar experience over C, C++ or, to an extent, Rust (which is another great language to learn).


Scala and Kotlin are an option on JVM, Aspire is basically catching up to Spring Boot, Quarkus, Micronaut, and Maddy Montaquila is on the record they are trying to use Aspire as means to bring developers into .NET, given the current adoption hurdles outside Microsoft shops.

Yes JVM currently sucks in value types and low level C++ like coding, .NET is great there, but not everyone needs those capabilities, and when they do, most don't shy away of doing some JNI.

On the technical level, .NET doesn't have GraalVM like tooling (it is a whole compiler framework not a plain AOT compiler), the MSR Phoenix project was canceled, Longhorn was canceled so nothing Android like, no real time GCs and bare metal deployments like PTC, Aicas and microEJ, no VMs for M2M, copiers, telephone switches.

In what concerns EF, I keep my point of view that I rather use Dapper with SP.


> kotlin are an option on JVM

I definitely liked writing Kotlin code in the past, but we had a medium sized Kotlin web api at a previous job, and a very large c++ app. The c++ app was quicker to compile than the Kotlin app on many many occasions, and the toolchain and IDE integration situation reminded me (not in a good way) of working with eclipse - even with intellij


I am not a big fan of Kotlin, given its community specially in Android circles, but the language is there as better Java.

Compile times might be an issue, I know it was an issue in the past.

C++ can actually be quite fast to compile, if the right decisions how to approach the build infrastructure and code styles were taken, which usually is not the case, hence its fame to slowness.


I can't trust any programming language where there's data structures I can't implement myself.


Generics really reduced the sets of data structures you can’t implement yourself by a lot.


What data structures can't be implemented without generics?


I don't think there's anything you "can't" implement that the language reserves for itself anymore. There may be some edge case or something but in general it's no longer an issue.

The language reserves syntax for itself; you can't overload a[b] to mean anything other than either array/slice indexing or indexing into a map. You have to write methods like ".Get" or something, there's no __getattr__ or anything.


Go has good (enough) built-in arrays and maps. But if you want a tree, without generics, you're really limited. With generics, you can get a nice containerized type, but you don't get the nicer syntax that the builtins have.

It's not just types, either. Look at the signature for the built-in sort, which is amazingly cumbersome to use. A generic wrapper around it hides all the ugly.


I think anything could be implemented, since you’ve got byte arrays in the language, which I imagine is your point.

It’s more what you must implement along with your new data structure to make it usable in the language that was the cry of the generics advocates.


i guess maps and array ? ( if you wanted to reimplement your own in a typesafe way, that is)


You are not the target market for go then. I personally think using Forth is fun, but not for large projects.


examples?


anything you can ‘range’ over :)


That’s been possible for a couple of releases now

In fact I created a struct that you can range over just a couple of days ago.

I can’t say I love the way Go implemented it though. But it does work.


>I can’t say I love the way Go implemented it though.

Why not?


It might just be user error on my part but it wasn’t entirely clear to me:

1. How it should be implemented “correctly”

2. The resulting code isn’t clear how it works at first glance (particularly with the yield command, it has “magical” properties that take a little effort to grok)

3. Requires calling a method

Example code: https://github.com/lmorg/Ttyphoon/blob/321738f289e4791e9674d...

I did write this at something like 11pm so it’s entirely possible I’ve done this completely wrong though.

Also please ignore the weird use of mutexes here too.

I’m also aware that sync.Map could/should have been used here. This struct was more of an experiment than anything that will ultimately find its way into production code.


In this specific case, one could do something like https://github.com/dharmab/skyeye/blob/main/pkg/radar/contac.... But your critique is still relevant for cases where you are generating/querying items on demand.


Thanks for sharing that. I’ll give that a play tonight.


You can range over the fields of a struct?


https://go.dev/play/p/Is1uwjRGASI

But I suspect they meant a struct which contains/encapsulates data which can be ranged over.


thanks


did not know this thank you!


Go added support for custom iterators a few versions ago.


I have written my own types that can do this?

EDIT: Had to check, yeah I had to implement the iter.Seq type to do it


> being a better Java for teams of mid-tier engineers.

That cuts me right to the bone.


Mid-tier engineers are the most dangerous type of engineer as they've learned enough to make decent abstractions and they tend to run with that over-engineering everything they touch.

IMO it is better said that Go is designed as being a good language for Senior and Junior developers, where mid-tiers will probably hate it.


This explains why I lost interest in Go right after it got generics and went back to Java (or Kotlin actually).

I do like to dabble in F# still.


In the end it was a dumb comment by one of the Go devs which got jumped on by all the Go haters. Contrary to the popular meme, Go's not just for mid-tier programmers - it never was (and to be fair to Rob Pike, they've twisted what he said). But sure, it makes it easier for programmers at all levels to get started, and to get real work done. That includes advanced people as well as the inexperienced.

I think the ultimate goal of making a programming language is to cause the least friction for a programmer trying to get real work done, and in my experience Go's great from that point of view. Language bells and whistles may be exciting, but often don't pay their way in terms of real world productivity, IMHO.


I have never understood why go fans think “make it easier for beginners” is an important feature. I mean, sure, it’s nice to have, but not at the expense of anything else — your career lasts 40 years; why optimize for the first month experience?


Pretty much every reputable computer scientist has been saying for the last 70 years that the most important thing in the entire world is simplicity and ease of understanding.


First of all, that is not true. But even if it were, those are not the same thing as how easy something is for beginners.

Abstractions make large systems easier to understand, not harder. Each line of Go is easy to understand, but whole programs are not.


>Abstractions make large systems easier to understand, not harder.

I raise you AbstractSingletonFactoryProxyBean.


Sorry I meant good abstractions, not all abstractions.


I like that meme graph with the junior programmer liking the simplicity, then the mid level programmer liking the power, then the senior going back to liking the simplicity.


> I have never understood why go fans think “make it easier for beginners” is an important feature.

Well, in the real world a lot of people have to work on teams where many of their co-workers never grow beyond beginner level. So anything that can be done to reduce the burden of having to deal with them is welcome. Not everyone gets to sit in the Silicon Valley ivory tower beside the greats.

> your career lasts 40 years

40 years is a peculiar number. If it is your passion, you should easily be able to see 60-70 years (assuming you live to an average age), and if you are only in it for the paycheque the comparatively high salary offers you retirement long before 40 years comes around.


> But sure, it makes it easier for programmers at all levels to get started, and to get real work done.

It is this condescending attitude that I feel many golang advocates (online) share that makes me shiver.

What are you implying, that devs using other languages don't get "real work" done?

Let's wait until Go has the same history, maturity and reach of e.g. Java and then let's see how well it will hold up in comparison.


Start a Java project and a Go one.

In the time you get everyone on the team to agree whether you should use Maven or Gradle, which testing framework to use, or figure out how to autoformat your code, your Go program will be done.


Meanwhile, start a rust project, and:

* everyone agrees to use Cargo

* everyone agrees to use `cargo test` (what even is a “testing framework”)?

* everyone agrees to use `cargo fmt`

What’s the advantage of go here?

By the way, the formatting situation is actually worse in Go because there are both gofmt and gofumpt used in the wild, at least gofmt has different behavior depending on different flags, and there are additional linters people use to e.g. ban long lines that for some reason the formatters don’t cover.


Yes, Rust copied all those good ideas from Go, so this is an odd argument to use.

I don't know why we're talking about Rust in the first place, but an obvious advantage would be compilation time and iteration speed in general.


The rust team will be bikeshedding a borrow checker error and debating if using unsafe is appropriate for some time after this, though.


Well, sure.

Let's wait another 15 year and then compare the new languages at that time against golang. Then let's see how golang is doing in comparison.


It may have been a dumb comment, but there's some truth to it. Go was to solve a Google problem of devs that needed to write system management programs, not systems themselves. The choices of Python or C/C++ left a large gap that Go filled.

I used Go for most of my own projects and as I got deeper into it began to realize its warts, but the worst was that you can't get performance by "share memory with communicating"--channels are slow. Reading the non-idiomatic stdlib implementation shows the difference of who it's made by vs who it's for (which isn't the authors).


> Go was to solve a Google problem of devs that needed to write system management programs, not systems themselves.

What's the difference? The opposite, so to speak, of system is script, and I don't think system management falls into the scripting category. A system management system is a system too. But that isn't what they were talking about anyway. They were talking in the context of building servers (think like a HTTP server). That was clearly spelt out.

I understand that the Rust crowd has reimagined system to mean something akin to kernel, much like they have reimagined enums to be akin to sum types. Taking established words and coming up with entirely new meanings for them is what they like to do. But that reimagining has no applicability outside of their little community. This is not how the industry in general considers it.


It’s funny you mention that: my on and off years with go have locked a couple (possibly wrong today) ‘rules’ for go; one is that channels are crazy slow, and another is that defer does not always work like you imagine it will.

There was a sort of misunderstood dream in the early days of go that it would make fanning out and using your 24 cores easy as empowered by channels: this is still not easy in go, although it may be easier and less error prone than c.

In the intervening decade, python has made say a parallel for loop immensely easier.


Not sure simplicity of spec translates into simplicity of user code. This change is backward compatible and will allow things that previously were disallowed.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: