
Go's Tooling Is an Undervalued Technology - dilap
https://nullprogram.com/blog/2020/01/21/
======
tsimionescu
Coming from the C# and JVM world to go, tooling looked like one of the worst
parts of Go.

The debugging story is very limited:

\- No function execution

\- No edit-and-continue

\- No conditional breakpoints

\- No watchpoints

Package management works OK on the consumption side, though it is much more
clunky than with classic package managers (e.g. set an ENV variable to get a
custom proxy, but write something in go.mod file to get a per-package proxy).
However, the publishing side is all over the place:

\- Relies on source-control integration

\- Horrible import paths for packages published from large repos

\- Versioning based on source-control tagging, exact format undocumented

\- Major version changes require source-code level changes in all files
touching the package

\- Multiple Go modules in same repo use-case is not documented (can you have
separate versions from same commit? how do they reference each other?)

The source-code level tools/plugins available are extremely basic (except for
GoLand):

\- No refactoring support other than "rename variable"

\- Reference-finding across modules rarely seems to work

\- No way to automatically find all implementations of an interface -
especially problematic in a language with implicit interface implementation

\- The tools are pretty slow, constantly re-parsing large chunks of code; go
pls has fixed some of that

~~~
Meai
Go also doesn't compile as quickly as people make you think. A regular sized
project will compile more slowly than a similar sized c# project.

~~~
coldtea
It's part of Go's typical "we assume/declare that we do better/simpler without
checking what/how other languages do" schtick.

Take error handling and package management for example - different approaches,
hacks piled, etc, instead of just going with the program, seeing how others do
it successfully (e.g. Maybe/Optional error, exceptions, etc), and get on with
it...

~~~
throwaway34241
Do you think Go's developers and users are simply unaware of exceptions,
optionals etc? Or is it that the trade offs that they made aren't net positive
for most use cases? Even if the second was true, that isn't necessarily a bad
decision; since C# continues to exist, there may be more use for a language
targeted to some niche than just a copy of C#.

I've used C# and Go extensively and like both languages. In some big ways they
are similar: garbage collected, (fairly) fast compile times, large ecosystems,
good tooling (if you include the JetBrains tooling for Go), built in
lightweight concurrency, etc. It's not surprising people compare them.

For the areas where they differ, Go in general is more explicit and more low
level. Handling errors as return values instead of exceptions is more typing,
but I find it easier to check that error handling has been done correctly in
my own code and in third party libraries. Instead of the class/struct
dichotomy pointers are explicit and any type can be used as a value type
(there's also more flexibility in using Go types with unmanaged memory, and
the ability to take interior pointers). The way interfaces are implemented
they can be used in more places without boxing.

C# has generics but I've run into frustrating limitations with them, for
example not being able to write numeric code that works with either 32 bit or
64 bit floats. Go's generics are currently limited to some built in types but
the proposals being iterated on seem like they'll be more useful to me than
C#'s implementation if they make it into the language.

Other things: Go has a single concurrency story so the ecosystem isn't divided
into sync/async worlds, is a less complex language overall, and is a bit less
verbose aside from error handling (no public static void etc). Overall I
probably prefer Go, but I like C# also and could easily imagine projects where
it might be a better choice especially in areas where the lower level aspects
of Go aren't useful.

Reading HN, it seems like a lot of people believe that people who use Go (and
even the language designers) are simply ignorant. I'm open to the possibility,
but can you flesh it out for me a little bit more? What am I missing here?

------
jcalabro
I definitely appreciate many parts of go's tooling ecosystem: pprof, gofmt, go
get (in GOPATH mode), and go bug are all pretty good ideas. pprof in
particular and the various profiling tools build out around it are great.

That being said, I haven't found all aspects to be as nice - most notably
among these is the lack of a good debugging environment. There is no debugger
in the go tool, and users rely on delve[0] for their debugging needs. The dlv
command line tool has actually gotten a lot better over the last couple years
(props to the maintainers!), but integration in to visual front-ends is still
lacking. VS Code and GoLand integrations at least are lacking to the point of
it being nearly unusable except in the simplest cases. For a few examples,
stepping is painfully slow (there are several machines/OSes I use),
conditional breakpoints don't seem to work, keeping the tools up to date
doesn't work consistently which means updating the underlying go/delve tooling
or the IDE will frequently break the experience, and defining your debugging
processes (e.g. via VS Code's launch.json) is tedious. None of these are go's
fault per se, but it diminishes the overall experience.

In general, it would be nice to have a better debugging experience, esp. since
I prefer a GUI tool to the command line for debugging. In the meantime, I
might switch back to just using command line dlv.

But regardless, definitely agreed that go's tooling on the whole is great.
pprof has saved my skin on countless occassions!

[0] [https://github.com/go-delve/delve](https://github.com/go-delve/delve)

~~~
odsb
Do people really use a debugger ?

This is a serious question because in 5+ years of programming I have never
used a debuggers. The only time I used a debugger was when I was learning to
program and to trace out for loops.

Now I just use print statements and read code to figure out what’s going on.

~~~
Koshkin
My impression has been that developers way too often rely on the subsequent
use of the debugger _when writing code_. It’s like, “I don’t really know what
I’m doing, but the debugger will help me _understand my code_... Oh, what a
piece of crap I wrote! Let me start over...” Looks almost like people are
debugging themselves.

~~~
pjc50
They're much more useful in maintenance environments where people have already
written a million lines of code before you got there. Of course you have no
idea what they've done. After a few years they probably have no idea either.
You can go grepping in the codebase, but the sheer speed of asking the
debugger "how did I get here?" is hard to beat.

They're also useful in layered environments. Sometimes it's a bug in other
people's code and you need to get in there to find out what's happening. When
all you have is disassembly, and can't readily insert print statements, the
debugger is absolutely invaluable. One of my own "debugger greatest hits" was
finding a bug in Windows CE stack unwinding this way.

------
kortex
When I first got into go, a few of the Go Opinions kinda rubbed me the wrong
way.

\- I have to source GOPATH in my rc files? Annoying.

\- File paths are network URI's? Ugly.

\- I have to deal with every err != nil? Verbose.

But over time I've grown to love go more than almost any language (python is
still bae, especially with type hints, and even then, it's close).

\- dependency pathing is a pain in most other languages. Singular source of
truth is great (I've had virtualenvs leak and cmake do bizarre things when
multiple libs are on the file tree)

\- host/paths are file/paths. I love this pattern now. It's just so obvious
and natural.

\- ok the err != nil still drives me nuts. But it drives me to write things in
a way where I don't need to deal with errors as much. Reduces fractal
complexity and paths through the code. It also forces "the buck stops here"
sort of pattern where you have some atrium which is resiliant and is where
most errors bubble up to

~~~
ShorsHammer
installing or updating go is still a massive pain, it's mind-boggling why
you'd have a modern language that behaves this way

~~~
ruffrey
I have not experienced problems installing or updating go in 5 years of use.
What problems have you experienced?

~~~
ShorsHammer
Nor have I had problems, simply saying it is too much hassle for little gain
so I rarely bother, whereas with other languages it is a breeze so I update
all the time.

Please document your workflow to update and compare it to other modern langs,
it's all relative.

~~~
AlexCoventry
This workflow works fine for me:
[https://github.com/golang/go/wiki/Ubuntu](https://github.com/golang/go/wiki/Ubuntu)

~~~
ShorsHammer
Ok so for ubuntu (which has what desktop share again?)

> _Add a 3rd party repository to apt_

> sudo add-apt-repository ppa:longsleep/golang-backports

> sudo apt-get update

> sudo apt-get install golang-go

> Note that golang-go installs latest Go as default Go. If you do not want
> that, install golang-1.13 instead and use the binaries from
> /usr/lib/go-1.13/bin.

> If that's too new for you, try:

> $ sudo add-apt-repository ppa:gophers/archive

> $ sudo apt-get update

> $ sudo apt-get install golang-1.11-go

Am I being trolled here?

How would you compare this for both memorability and user experience compared
to say "rustup update"?

Please take a step back and look at that question without personal bias.
Please!

~~~
jorams
This comparison is entirely unfair, because you're not comparing the same
thing. This is what one has to do to install Rust:

    
    
        # Install rustup
        curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
        # It automatically installs the latest version
    

This is what one has to do to install Go:

    
    
        # Add the PPA
        sudo add-apt-repository ppa:longsleep/golang-backports
        # Fetch information from the PPA
        sudo apt-get update
        # Install Go
        sudo apt-get install golang-go
    

1 command vs 3, but in both cases only one "odd one" you have to remember
specifically. More important, however, is the fact that from now on Go will
update along with the rest of you system. You upgrade your system like this:

    
    
        # Upgrade the system
        apt-get update && apt-get upgrade
    

rustup turns that into the following:

    
    
        # Upgrade everything
        apt-get update && apt-get upgrade
        # Upgrade Rust
        rustup update
    

Now I'm not trying to say rustup is necessarily worse than Go, because it does
offer advantages, but for the simple use-case of always running stable it adds
an extra step rather often, instead of once.

~~~
ShorsHammer
>This comparison is entirely unfair

Updating rust: "rustup update"

Updating Go: Search a bunch of stuff and then do the stuff some random website
tells you.

Entirely stand by my earlier statements. Apparently the thousands of paid
computer scientists at google are simply incapable of automating the basic
process to update their lang. It's utterly absurd and should be actively
mocked by anyone with half a clue. We should mock this stuff, we really
should, it's hilariously dumb.

How are all the people getting paid SF wages literally incapable of creating
"go update"?

~~~
jorams
> Updating Go: Search a bunch of stuff and then do the stuff some random
> website tells you

No, updating Go just happens when you update your system. You don't need a
separate command to do it. All of the other stuff you mentioned in your
previous post is about _downgrading_ Go.

------
pjmlp
Go would be about right, had it been released around 1992, when we had Oberon,
Oberon-2, Component Pascal, Modula-2+, Limbo making the university rounds.

As it is, I see it mostly as C replacement.

Yes, as C replacement, as projects like TamaGo, Android's GPU debugger, gVisor
hypervisor, Go's bootstraped compiler, Fuchsia's TCP/IP stack, TinyGo for
microcontrollers, show.

However for anyone that enjoys being able to take advantage of what happened
since 1992 in mainstream computing, Go isn't it.

~~~
cube2222
This is backwards in my opinion and omits a lot of nuance.

There is no other mainstream language which combines seamless async-
everything-to-the-ground with good performance.

Whenever I write in another language I feel like I'm in the stone age only
because of this one feature already.

~~~
pjmlp
C#, VB.NET, F#, Erlang and Elixir come to mind.

~~~
cube2222
I've used F#, it uses computational expressions for async functions. And
functions are either async or not. Same for C#. Same for Scala, Haskell and
others. Future[T] is so unergonomic and it creates a huge divide in the
ecosystem. Been there, hate it.

I understand why Rust made the choices it made, they're going with zero cost
abstractions, but for other kinds of languages async everything is fundamental
to me after having used Go.

Erlang and Elixir are not fast, they use C implementations of functions for
computationally heavy code, which of course blocks the scheduler for the
duration of the call as far as I know and also can bring the Erlang VM down
with exceptions. But yes, ergonomically wise they are what I want in this
context.

Java Loom seems to be trying to add transparent asynchronicity, but it's not
here yet.

In Go I write straightforward seemingly blocking code, and it just works.

~~~
pjmlp
It just works is not what I would call writing into possible closed channels
or eventual deadlocks accessing shared data.

~~~
cube2222
Writing to closed channels never happened to me in practice. Sure, you have to
write idiomatic go code but then it's a Non-Problem. Deadlocks are indeed a
problem but at least there's the deadlock detector which crashes your app with
a stacktrace which makes it a minor inconvenience in practice.

Being able to launch a goroutine for background housekeeping, like sending
keepalives, in a structure constructor without thinking much about it is
extremely liberating to me.

My point is that Go is not extraordinary in the language constructs it
presents. It's extraordinary in its implementation, from-ground-up async and
the family of problems it completely abstracts away.

I'm not saying you have to agree with me in that Go is the best languag for
you to use. But suggesting it's a language which feature wise is left behind
in the 80's is plain dismissive and makes you seem uninformed to anybody who's
written any nontrivial amount of it

I've written code in most of the languages you've compared it against. Even
explored heavy functional approaches. And even though they were interesting,
often innovative, Go still leaves them behind in the dust in practice for me.
Because it hides the stuff I don't care about and works well for creating
real-life software which I later have to operate, extend and extinguish when
it's burning in prod.

Edit: Just to add, implicit interface implementation is great for composing
software.

~~~
pjmlp
I hardly see the difference between,

    
    
        go func () { }
    

and

    
    
       Task.Run(() => {})

~~~
shadowgovt
You can't? Perhaps this is why you encounter writing to closed channels and
deadlocks accessing shared data.

~~~
pjmlp
Please enlighten me how it is less error prone than TPL and Dataflow.

------
kstenerud
Go's tooling is very nice compared to most other dev technologies, and the
source is quite hackable as well. I made a 1-commit modification to the
compiler that adds a flag -warnunused to make it stop failing on unused
imports or variables [1], and it was remarkably simple to do in the go src
tree.

Plus, it's super easy for other people to use. Just check out the modified
source, make.bash, and you're done in less than a minute of compilation!

I may not agree with some of their philosophies, but the tooling is nice!

[1] [https://github.com/kstenerud/go](https://github.com/kstenerud/go)

~~~
candiddevmike
Can you expand on the use case for your change? Why would you want unused
imports or variables?

~~~
kstenerud
When I'm debugging something, I don't want compiling to fail just because I've
commented out the only line that uses the net/url package. If I temporarily
modify a function call to use a literal instead of a variable so I can test an
assumption, I don't want it to refuse to compile just because that variable is
now "unused". The cascade effect of this can get quite extensive and annoying.

Same goes for exploratory programming, where I'm testing out ideas rather than
writing production code. I expect my tools to get out of my way rather than
play nanny.

~~~
loopz
Alternatively just add usages at top of package that have no real effects.
This is experimental code after all! Never had problems with this, but yes,
it's a bit different.

~~~
bschwindHN
So many silly workarounds being suggested here. You should be able to pass a
flag to accomplish this, anything else is simply annoying and drives away new
users.

~~~
loopz
That's a feature!

You could have a flag, but we all know this is going to be abused. Seems devs
have opted away from such, though it is understandably opinionated and require
some thought.

~~~
kstenerud
In what way would it be abused? "To use this library, you must enable warnings
in your build"? Yeah, that's gonna fly. If your code won't compile with
default options, nobody will want to use it.

This is just a solution in search of a problem.

~~~
loopz
Isn't such types of shenanigans SOP in many communities?

Not against options per se, but can see the arguments against implicitly
hiding alternative behaviour. Many compilers fail to be simple, performant and
provide the right incentives.

Again, never had problems adding experimental code (// TODO: Remove),
bootstrap-code, extra debug-info, etc. Ie. Why you should want to prefer
refactoring.

------
chris_overseas
> If you already have a Go compiler on your system, there’s no reason to
> bother with binary releases. Just grab the source and build it. All can
> manage their own toolchain with ease!

No thanks, give me binaries any day. I want to spend time developing my own
software, not fiddling around bootstrapping a dev environment.

~~~
philwelch
I agree with you and I found this part of the article strange as well, since
one of Go's strengths is that it routinely spits out self-contained binaries
thanks to doing exclusively static linking.

------
nerdbaggy
I love all the other commands for Go. I love the pprof, it’s so powerful.
[https://golang.org/pkg/net/http/pprof/](https://golang.org/pkg/net/http/pprof/)
and all their other commands are great
[https://golang.org/cmd/go/](https://golang.org/cmd/go/)

------
jayd16
Eh, Java and C# and I'm sure plenty of others make this pretty simple as well.

Go does seem to currently benefit from simplicity through lack of choice as it
seems like there's only one way to do things, which is nice. I assume that'll
eventually change as its not something you can really protect against and more
the burden of success.

------
atilaneves
... compared to C and C++.

The reason why header-only libraries exist is because C and C++ don't have an
official package manager. That's it. Any other language that does can vendor
just as easily. Similarly, pretty much every other language has package
management so that's not a point in Go's favour.

From the article, we're left with compilation speed. That's actually
important, but Go isn't the only language that has a reference compiler that
runs fast!

~~~
pornel
Also error messages from the tooling are still from a previous era. Nowadays
tools say not just what's wrong, but go an extra mile to explain why and how
to fix it. Go tools still print "go: your command was bad and you should feel
bad. exit".

------
tmountain
As an additional plus, you can apple-click "builtin" functions from inside of
VSCode and drill into core libs for debugging purposes (adding breakpoints,
log statements, etc). I've done this on a number of occasions to quickly get
the result from an external HTTP request, etc. Go truly feels like a hacker's
language that lets you get under the hood really easily when necessary.

~~~
mhh__
Is that not normal? The only languages I don't do that in (if needed) are C++
(STL code makes my eyes bleed), and C (no need - too basic).

That being said if you need to add a breakpoint into stdlib code then God help
you? (never used go so can't comment)

~~~
ebeip90
Setting breakpoints on CPython native code is a PITA and can’t be done (afaik)
from PDB.

~~~
1337shadow
Doesn't b do the trick for you ?

b(reak) [ ([filename:]lineno | function) [, condition] ] Without argument,
list all breaks.

    
    
            With a line number argument, set a break at this line in the
            current file.  With a function name, set a break at the first
            executable line of that function.  If a second argument is
            present, it is a string specifying an expression which must
            evaluate to true before the breakpoint is honored.
    
            The line number may be prefixed with a filename and a colon,
            to specify a breakpoint in another file (probably one that
            hasn't been loaded yet).  The file is searched for on
            sys.path; the .py suffix may be omitted.

~~~
ebeip90
This breaks on Python code, not CPython native (C) code

------
thayne
There are definitely good things about googles "decentralized package
management". But using a url for the import also causes problems. What if the
url the code is hosted on needs to change? And then I also ran into a case
where I wanted to fork a dependency of a project, so I could get a bug-fix
that hadn't been merged into upstream yet. But the only way I could figure out
how to get it working was not only to have to change all of the imports in the
main project, but a bunch of imports in the dependency as well to point to the
fork. This seems needlessly painful.

~~~
didibus
Are we all going to pretend like we forgot Java has been using URIs for
imports for 20+ years?

~~~
masklinn
The difference is that java’s “uris for import” is nothing more than a
namespacing convention to avoid conflicts. A url in go is the actual place
where `go get` will go retrieve the dependency, and the directory it’ll live
at.

~~~
didibus
That's true, thinking from that angle it does seem more troublesome then, in
cases where the URI goes down, or changes, or you need a personal fork.

------
luord
> [anything related to Go] is an undervalued technology

What exactly has he been reading? I've been working in Go for a while now,
after years of reading only praise for it. Except for the error handling,
which is far from the only thing wrong with the language/ecosystem, and even
comments on that never fail to gather dozens of apologists.

There's nothing undervalued about it. This article itself is an example and it
features little I haven't read dozens of times.

> Decentralized modules are great idea and avoid most of the issues of a
> centralized package repositories.

But centralized package repositories are essentially an attempt to solve the
problems of the wild west approach from before (which Go's way is more or less
a throwback to, that only works better now thanks to platforms like github).
Maybe they're a good thing? Is everyone else wrong? Questions for later.

------
thrwaway69
The part about building go is neat in comparison to other languages. I don't
see the fresh breathe of ideas in package management. People used to host code
and directly import it before go even released publicly. Go get was a thin
wrapper over traditional way of downloading code and putting it in your
folders if anything (wget). Ignoring the other advancement that took too long
for go package management situation to resolve, currently I don't see any
advantage go has over other languages in that area. Node package managers have
allowed you to install packages from "decentralised" sources such as github or
gitlab for a long time. node_modules is similar to vendor and with nexe, you
can package them all into a single executable. Cargo provides all of that with
additional features that neither of them do.

Go developers butchered community experiment in the form of dep. While it had
many problems but those didn't require abandoning it out of nowhere, this
isn't the first time that has happened. The community has a knee jerk reaction
to anyone providing suggestions to change something or better it. Failure of
go type system (other than generics) is often met with suggestions of code
generation and doing some wackamole interface magic. To any problems in the
standard tooling, the answer is to fork it and go away. I agree but other
communities don't behave that way.

People are separated into distinct camp when it comes to promises or
expectations. One noticeable idea is simplicity, half the crowd believes in
the notion of verbal/syntactical, keywords and typesystem having less
"features" simultaneously fighting for less ambiguity. The second half base
simplicity on putting graduates to get up and working quickly in a code base
at the cost of long term complexity in abstractions. All ideas of go make
sense if you think from large company's perspective.

You can notice how go would work well in a company with monorepos.

That said. I hate go but that's why I like it too. If I want to get something
done, I choose go. If i want to hack something and appreciate beauty of
developing rather than efficiency or reaching end product, I avoid go like
plaque.

------
didibus
I don't really see how the package management in Go is better than in Java? In
fact, it seems a bit inferior on some aspects, though mostly similar sounding
overall.

Can someone more familiar with both explain?

I have to admit, the Go compiler is what I'm jealous of. No dependencies, not
even GLIBC and cross compilation seems a breeze. SubstrateVM has a lot to
catch up too there.

------
m463
I enjoy this sort of craftsmanship in software.

It's also a very practical way of assuring wide adoption.

A weird side-effect is that it makes mediocre software just that much more
annoying and easy to bail on.

------
spectramax
I played around with Go for the first time. The package manager and process of
creating a new project was refreshing! It’s so tidy and neat. Those are the
first words that I thought of - Go is a very tidy and neat language. From
syntax to publishing packages, the language has extreme levels of cleanliness.

------
ggregoire
I expected a section about testing and benchmarking since it comes out of the
box with Go. Are there other popular languages offering it?

~~~
steve_adams_86
Python has the unittest module which works well for basic unit testing, and
it's inspired by others (JUnit and the smalltalk testing framework
respectively as I recall). I'm not sure about benchmarks, though.

~~~
ggregoire
Well, TIL! I had no idea about the unittest module. I always see pytest used
in Python projects.

~~~
sitkack
That is because unittest should be removed from the core libs. It is a bad
copy of a Java library, pytest is far superior in every way. There is no
reason to use unittest.

~~~
masklinn
Well there’s the reason that it avoids pulling in a dependency.

Which arguably is not much considering all the benefits of pytest.

~~~
sitkack
If you are airgapped, you have other problems. They weren't really my target
market.

------
_pmf_
It's probably because Go programmers come from Java, where tooling is
similarly great or better.

------
pbnjay
I find go doc, go fmt, go vet, gopls, etc to be much more undervalued than the
compiler itself. I use these supporting tools much more frequently than I
invoke the compiler (yeah they're related...) but TBH the huge selling point
when I point people to Go is the developer support and ecosystem.

------
rezeroed
The article has three sections: building Go, package management, and
vendoring. The first is irrelevant to almost everyone. The other two are
terrible. If that's supposed to be singing Go's praises then I think it says a
lot that wasn't intended.

------
eeZah7Ux
The level of hype around Go is absurd. The packaging and vendoring is a
disaster. Not only the implementation, but the idea itself.

------
arcticbull
Go's compiler toolchain is an overvalued monstrosity, a relic from the 70's
only Rob Pike could get away with resurrecting. Imagine walking into your day
job and saying to solve today's problem you're going to blow the dust off your
old floppy disks and see what they've got in store.

It's like Tesla deciding that before they built a car, they'd have to pave a
new highway from SF to LA. Someone's already done the paving, focus on what
you bring to the table.

LLVM is clearly the future. Yes, it could be improved, but of course all the
effort that went into resurrecting the geriatric Go compiler didn't go into
improving LLVM. It went into re-implementing assemblers for various
architectures as though that wasn't a solved problem 100 times over.

As for package management and vendoring, both are great, and should be table
stakes, so credit where due on that one.

~~~
kortex
And yet it works, it's fast, it's reliable. I've tried to build clang and it
aint pretty.

Something something shipped is better than perfect.

IMHO I'm quite glad they didn't drag the bloat of LLVM into the fray.

~~~
randomdata
Besides, one of Go's explicit goals was to not be bound to any one
implementation. The language has been carefully documented to ensure that
anyone could reimplement it without having to understand nuances of a specific
toolchain.

If you want to compile Go using LLVM, everything you need is there to make it
happen. In fact, someone has already done a lot of the leg work for you[1].
And if GCC is more your thing[2]...

[1] [https://tinygo.org](https://tinygo.org)

[2]
[https://golang.org/doc/install/gccgo](https://golang.org/doc/install/gccgo)

~~~
millstone
I think this is too facile. Go was conceived as suitable for systems
programming tasks, like web browsers, databases, and operating systems. But
Google's own web browsers, databases, and OSes do not use Go.

It was also conceived as suitable for web servers, crawlers, and indexers;
there it has been successful inside and outside Google.

Why didn't it catch on for browsers, databases, OSes - while Rust did? I think
it must be the GC primarily, but the lack of an advanced optimizing compiler
is part of the story.

~~~
randomdata
I'm not sure where the idea Go hasn't caught on for databases comes from.

* [https://awesome-go.com/#database](https://awesome-go.com/#database)

* [https://github.com/rust-unofficial/awesome-rust#database](https://github.com/rust-unofficial/awesome-rust#database)

Rust was invented specifically to write a web browser, so that is a bit of an
unfair comparison, but I would suggest that Go's lack of seamless inter-op
with C is its biggest limiting factor in integrating into existing browser
codebases as well as greenfield GUI applications. Additionally, Go's runtime
is not well suited to OS development.

I doubt the lack of an advanced optimizing compiler ever crosses anyone's mind
as by the time that might become an issue they have already ruled out Go for
its many other limitations.

