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

Go is not quite the same but definitely on a similar level of abstraction to C, C++, Rust, etc. If that statement makes you raise an eyebrow, I'd suggest that while Go requires more runtime than C or Rust, it does still give you:

- Direct memory access through `unsafe`. Python kinda does through `ctypes`?

- Tightly integrated assembly language; just pop Go-flavored assembly into your package and you can link directly to it.

- Statically-compiled code with AOT; no bytecode, no interpreters, no JITs.

Therefore what really sets Go apart is that it gives you all of these rich standard library capabilities in a relatively lower level language.

Of course I kind of understand why Rust and C++ don't put e.g. a PNG decoder in the standard library, I think this is somewhat an issue of mentality; those are things that are firmly the job of libraries. But honestly, I wish they did. It's not like the existence of things in the standard library prevents anyone from writing their own versions (It doesn't stop people from doing so in Go, after all), but when done well it provides a ton of value. I think nobody would claim that Go's flags library is the best CLI flag parsing library available. In fact, it's basically just... fine. But, on the other hand, it's certainly good enough for the vast majority of small utilities, meaning that you can just use it whenever you need something like that, and that's amazing. I would love to have that in Rust and C++.

And after experiencing OpenSSL yet again just recently, I can say with certainty that I'd love Go's crypto and TLS stack just about everywhere else, too. (Or at least something comparable, and in fairness, the rustls API looks totally fine.)



> Direct memory access through `unsafe`. Python kinda does through `ctypes`?

Already available in ESPOL and NEWP (1961), Modula-2 (1978), Ada (1983), Oberon (1987), Modula-3 (1988), Oberon-2 (1991), C# (2001), D (2001) and plenty others I won't bother to list.

> Tightly integrated assembly language; just pop Go-flavored assembly into your package and you can link directly to it.

Almost every compiler toolchain has similar capabilities

- Statically-compiled code with AOT; no bytecode, no interpreters, no JITs.

Like most compiled languages since FORTRAN.


> Statically-compiled code with AOT; no bytecode, no interpreters, no JITs

Except in reality in does not work, like you can't easily create a single binary out of most C/C++ project.

You always going to fight with make / GCC / llvm and other awful tools with errors that no one understand. It does not matter if the underneath tool / language is supposed to support it, can a developer make it work effortless or not.

In Go you download any repo type go build . and it just works. I can download a multi millions line repo like Kubernetes and it's going to work.


Depends on the C compiler one decides to use.

If you believe that regarding Kubernetes you're in for a surprise regarding reproducible container builds.


Huh? I think you misinterpreted what I meant to suggest that those features individually were unique or unusual. I was only using them to demonstrate that Go is on a similar level of abstraction to the underlying machine as C, C++ and Rust.

> Like most compiled languages since FORTRAN.

Yes. But you didn't list "compiled languages since FORTRAN", you listed:

> Python (1991), Java (1995), .NET (2001), Smalltalk (1972), Common Lisp (1984), Ruby (1995), Perl (1993).


First of all I never mentioned that I wrote an exaustive list of compiled languages since the dawn of computing, rather a reply to

"Go's standard library is a shining example of what all standard libraries should strive for. Yet, we still have some languages who's developers refuse to include even a basic http API in their standard libraries in an age where even embedded systems have started to speak http. Imagine if if the same had happened with TCP and UDP...

Here's to the continued success of Go and other sanely-designed languages."

You then moved the goal posts by talking about stuff that wasn't in that comment.

As such I am also allowed to move my goal, mentioning that

"Already available in ESPOL and NEWP (1961), Modula-2 (1978), Ada (1983), Oberon (1987), Modula-3 (1988), Oberon-2 (1991), C# (2001), D (2001) and plenty others I won't bother to list."

Are all languages that compile to native code.

"Ah but what about C#?!?", it has had NGEN since day one, Mono/Xamarin toolchain has supported AOT since ages, Windows 8 Store Apps used MDIL toolchain from Singularity, replaced by .NET Native for Windows 10 store apps, Unity compiles to native via their IL2CPP toolchain, and nowadays we have Native AOT as well.

And I will had that Java has had native AOT compilers since around 2000, even if only available as commercial products, with Excelsior JET, Aicas, Aonix, Webspehre Real Time, PTC, and unsafe package as well, even if not enjoying an official supported state (nowadays replaced with Panama for exactly the same unsafe kind of stuff and low level system accesses)


I do not understand how you and some other people seem to see a claim to be first in every feature a language ever says it has. Who is claiming primacy or uniqueness for almost any feature in any language ever? When has a Go designer ever claimed to be the first ones to implement a feature?

Programming languages have been largely just shuffling around features other languages have for the last 50 years now, and I can only go back that far because when you get back to the very first languages, they're unique and first by default. Even when a language is first to do something, it's generally only the first for a feature or two, because how would anyone even make a programming language that was almost entirely made out of new things anymore? Even if someone produced it, who would or could use it?

You seem to spend a lot of time upset about claims nobody is actually making.


It is the way people insist on writing such arguments.


I don't know what your goal in this discussion is. I don't think anyone is claiming Go invented having a nice standard library, nor is anyone claiming that Go invented compilers or anything weird like that. I think you misunderstood the entire discussion point.

On a similar note, iPhone did not invent cameras, MP3 players, cellular broadband modems, touchscreens, slide to unlock, or applications.


I think if the Rust team had the capacity they might have considered adding—and maintaining—more stdlib functionality. I never asked for details but I guess that the core Rust enjoys only a fraction of the funding Go and .NET have enjoyed. It’s not only a merits based decision case I think.

Regarding C++, it’s based on a standard, the situation is a bit different. You have a variety of implementations. Imposing anything beyond the typical use case the compiler implementations have catered to would induce an insurmountable overhead on the implementation coherence. Therefore, I believe it’s more reasonable to have application-level logic in the realm of community maintained libraries. In addition, C++ is huge syntactically and the stdlib is immense, but it’s more focused on algorithmic tasks rather than on quickly building mini-servers.

Besides, the Go community has a myriad of reinvented wheels, ranging from logging over caching to maps, and until recently HTTP server libraries. The logging story for example has just recently led to a discovery of the patterns desired by the community, mature enough to accommodate structures logging in Go’s stdlib. Similarly for error handling. Robust and settled approaches turned a de facto standard make total sense to be included.

.NET is different again, having a center of gravity with Microsoft and the .NET Foundation, with typically one preferred library for a given task, contrary to Java and Go. Centralized and decentralized, the classical dichotomy.


I think Rust team would still have a very small stdlib even if they have more funding, here's a talk[0] where they aim to be relevant for the next 40 years, in that time span there would be a lot of changes and to be backward compatible, you cannot have features in your stdlib that will be irrelevant or change in the next 5, 10, 15, 20 years.

[0] https://www.youtube.com/watch?v=A3AdN7U24iU


That’s a great point indeed. In Java and C++, there have been quite a few deprecations over the years and decades. In the Rust community, there’s unfortunately quite a lot of interesting but abandoned crates.


What changes are set to be made to the file format of PNGs that would prevent it from being relevant in the standard library 40 years from now?


[flagged]


I agree with everything besides the single language.

Something like D or Nim would also count, although I do grant they feel like toy ecosystems when comparing with .NET.


> it isn't, I know how a good one looks like)

Good. Just don't tell others lest they point out many shortcomings in your choice.


Well, would you like to?


what about Julia? it has all the low level features you would want and it's structs are c compatible.


Unfortunately, I know very little about Julia aside from hearing good things about its application in scientific domain and it having interesting options for accessing SIMD which are similar to C#'s SIMD API. Someone else here could perhaps provide better context.


> Go is an extreme parody of C mindset adapted to kindergarten level of risk

There's nothing of substance actually said here so it's hard to refute or support it very much.

> so that Google could tackle its internal dev culture issues.

Only one sentence in and this sounds like a vague reference to that thing Rob Pike said one single time 10 years ago or whatever, but I don't really care why Go was supposedly created or what it was for over 10 years ago, I care about what it is today. I think you can do better than this.

> There is only a single high-level language with GC today that exposes appropriate low-level primitives and it is C#. In C#, you can declare C-style struct and pass it directly to C code across interop without any marshalling whatsoever. You cannot do this in the way everyone uses Go.

I dunno what you mean exactly, you certainly can declare a C-style struct in Go. You can declare it using C, or you can pass a Go-defined struct into a C function, it follows roughly the same alignment rules, I do this all the time when coding against Win32 APIs. It's in fact better than it used to be because there is now a way to pin memory so that it is safe to pass Go pointers directly to C code, using `runtime.Pinner`, but certainly there was no limitation to using structs the C way before. There aren't many guarantees about memory layout, but there wasn't in C either.

> I'm also amused by how "AOT" is one of the biggest demonstration of "X Y issue" in practice where developers have little understanding of how each platform can have drastically different ways of achieving "lean fast to start applications". What's unfortunate in this is they make Go's AOT as a selling point, where it's just its deployment model, at which it's not even the best nowadays

OK... but for context... I was literally only trying to demonstrate that Go is a relatively low-level programming language in terms of how close you are to machine code, putting it in a similar camp to languages like C and Rust, rather than something like Python. It is not an argument in favor of a given way of packaging or executing software. You can of course make programming language implementations with different tradeoffs, but I don't think it's accidental that scripting languages, compiled bytecode languages and compiled machine code languages tend to have different attitudes, I'm of a mind that they are mostly the way they are because of the characteristics that would lead someone to reach for one versus the others.

> you will be much better served by forgoing Go in favour of Rust or C#

I don't think there's any reason to disagree that Rust is a great choice of programming language. Rust has numerous amazing advantages versus most other programming languages, offering an excellent set of guarantees. However, it does so by paying a lot of language cost to get there. I'm not saying, for example, that this means that Go is good at some use cases and Rust is good at others, I'm saying that Go and Rust have some overlap at what they are good at and they have some areas where one will have nicer tradeoffs than the other. Rust handily has the advantage for writing concurrent code, which is ironic given Go's name and how much its concurrency model was emphasized early on. But Rust is a very, very complex programming language; sometimes what it goes through great, great pains is something that you absolutely, 100% want to have, at any cost, and sometimes it's just not. When dealing with embarassingly parallel programs like network services with nothing-shared architectures, Go shines; it's pretty good at these. When every CPU cycle and byte counts, Rust wins against Go every single time, because it offers greater control and vastly more powerful compile-time metaprogramming. (Go offers essentially none, since even generics mostly compile down to interfaces.) Does the complexity always matter? Well, maybe not, but you'll notice in compile times.

> please do not tell me about how good Go's standard library is - it isn't, I know how a good one looks like

This is a shallow dismissal that shouldn't really convince anyone since it doesn't even attempt to paint the picture so I will reply with a retort of the packages in the Go standard library that I think are pretty great and I would like to have in other programming languages.

- Literally all of `crypto`, including `crypto/tls`. To be completely fair, I wouldn't argue they are perfect (`tls.Config` is a little weird) but they are very clean and reasonable implementations of cryptographic routines including some nice optimized assembler code across many architectures for plenty of them. The actual interfaces are pretty good and help to avoid some basic pitfalls. It is relatively easy to e.g. create and sign an X509 certificate, versus OpenSSL.

- `regexp` - Neither the fastest nor the most fully-featured regular expression engine. On the other hand, though, it gives you re2 behavior - the same featureset, and the same runtime behavior, specifically that it scales linear with time with regards to input size. That makes it a rather good library to have as a default choice, since it is significantly less likely to wind up as a surprise footgun that way, versus say PCRE.

- `image/png`, `image/jpeg`, etc. They're neither the best nor the worst PNG or JPEG encoders/decoders. But they're PNG and JPEG decoders, in the standard library, and the speed they perform at it seems acceptable, and they're memory safe. For doing any serious amount of image processing, I'd rather shell out to libvips, but there are a lot of use cases where it's tremendously nice that there's basic codecs like this in the standard library. Same for the compression algorithms in `compress` and the archive implementations in `archive`.

- The `go` package. Like most of the other packages, there's nothing terribly astonishing about this package. However, it does give you enough Go compiler guts to go ahead and parse and work with Go code. This is very useful because inevitably with large codebases you are going to want the ability to write accurate static analysis tools, make code that can do large tree-wide refactors, and other such tasks. For C++, you probably have little choice other than to use Clang's AST. For Rust, the closest I'm aware of is the `syn` crate, but I might be out of date here. These options generally require a great deal of effort to do even rather simple things, making it rather hard to get to the point of break-even for them, and I think that's not great. Some of this is definitely due to language complexity, but that is indeed a cost you have to pay multiple times. So it better be worth it!


The regexp being "not the fastest" might be an understatement: https://github.com/BurntSushi/rebar?tab=readme-ov-file#summa...

Nothing that Go has is uniquely better or even competitive. Both C# and Java have way more extensive and optimized standard libraries. What Java has working against it is the lack of structs, monomorhpized generics and SIMD API to ensure all standard library bits stay as performant as they are in .NET, but nonetheless the areas that have no use of those are optimized to a comparable degree. And you can be sure they offer sufficiently good support on all major platforms: Linux, macOS, Windows and, what is a major Java/Kotlin's advantage, Android. Something that Go treats with pretending like the only platforms that exist is UNIX/POSIX.

There are other things, like Go's blessed way of slicing strings being problematic because it does nothing to prevent you from tearing code points so you have a lot of code that might be silently corrupting text data.

And for interpreting AST, this exists in both Java and C# with different strategies. C# approach is a bit more complex but extremely powerful with build-time source generators that have full access to AST generate new code, fill out existing partial members or intercept calls, and does not require any external scripting. A good example of that is generating gRPC clients and servers code from .proto file by simply executing `dotnet add package Grpc.Tools` and adding .proto reference to .csproj.

Go may seem like a good language after coming from scripting nightmares, it may even seem like a good systems programming language that is easy to use. I promise, it is not. In order to call intrinsics, in C#, I just call them because that's what it offers, in Go, I have to write asm helpers manually.

If you look at what modern C#, Kotlin and, again, Rust provide in their respective areas, you will soon realize that Go does not have anything to offer that is unique or better, except perhaps the culture of minimalism, which other ecosystems are also advocating for in at least last 5 years.

p.s.: I forgot to mention the reason interop was brought up - in C# it can be zero cost or nearly zero cost because it is something that was considered at the language and platform inception. It is one of the reasons C# will never use green threads and eventually will move over upgraded runtime handled task system (mind you, current day state machine implmentation works well, but can be improved). The cost of FFI in Go, unless you use Cgo, is dramatic. This is something that is not acceptable for a language positioning itself as a systems programming one.


> The regexp being "not the fastest" might be an understatement

Good benchmarks, but what you are seeing are the consequences of the fact that Go's `regexp` engine isn't very optimized, it implements a fairly naive NFA-based regular expression engine. This is perfectly reasonable for simple use cases like input validation or parsing simple string formats, it's plenty fast in that case. When you throw a complex regex with backtracking you can see performance drop severely compared to other engines. If you throw a regular expression that does not have backtracking or case insensitive literals it performs reasonably well and executes it in one pass as you'd hope.

Of course if you were writing something like grep where the throughput is directly tied to regexp execution, yes, you would most certainly want to pick an optimized regexp engine, though it would likely come at the cost of needing a JIT and other complexity.

The existence of `regexp` in the standard library, though, certainly doesn't stop you from picking a more optimal library, any less than it does for JSON parsing for example.

> Nothing that Go has is uniquely better or even competitive. Both C# and Java have way more extensive and optimized standard libraries.

I think that it is very nice when standard libraries contain "optimal" implementations of things, but in most cases it's not the most important concern. Having sufficient implementations of things is much more important. And in that regard, Java is far from the worst, but it's also far from the best, too. For the longest time, Apache Commons was treated as a defacto-standard library for Java programs, I'm sure you've experienced this. Most of the stuff in Apache Commons is stuff you can also find built-in to Go.

> What Java has working against it is the lack of structs, monomorhpized generics and SIMD API to ensure all standard library bits stay as performant as they are in .NET, but nonetheless the areas that have no use of those are optimized to a comparable degree.

Honestly, Java's performance was never that bad, it is/was specific things that really caused it to suck, like objects, reflection, the GC. Some of it has been improved greatly, in part thanks to ZGC and other innovations, but Hotspot was always pretty good at running tight loops and computations at a respectable speed.

What makes Go nice is that it just doesn't need as much optimization to begin with. It's funny to compare Go code to highly complex and optimized code all of the time, but this happens mainly because it still often competes in the same class despite being kind of dumb and simple by comparison, for a myriad of reasons. The Go GC is probably technically not as optimal as the latest and greatest Java technology, but it doesn't really matter too much because Go manages to do a better job at preventing objects from escaping to the heap in the first place. Java is recently getting on this train, too, but it's got a long road ahead, as Java code and interfaces will need to be adjusted to try to minimize unnecessary escaping to fully exploit this. A lot of common Java patterns don't make this easy.

> And you can be sure they offer sufficiently good support on all major platforms: Linux, macOS, Windows and, what is a major Java/Kotlin's advantage, Android. Something that Go treats with pretending like the only platforms that exist is UNIX/POSIX.

What is wrong with Go's support of Windows or Android? I use Go for Windows programming all the time. I was even working on writing a Win32 language projection for it, but I lost a bit of the code and haven't had time to pick it back up. Go ends up being nice to use with native Windows APIs especially since you can dynamically link to libraries without needing CGo.

Meanwhile, Java programs seem to have a harder time dealing with platform interoperability than Go programs. For example, ANTLR4 still seems to have issues handling paths with backslashes: they work, but the relative path calculations that are done are wrong, resulting in different behavior/output. I choose this as an example because it's a really popular and not particularly new Java program, but it's also the latest iteration, showing that Java platform interoperability issues are nothing new. It's, of course, not Java's fault that Java programs may contain bugs; but it is Go's work that has made it less likely for Go programs to make this mistake by designing the standard library to make path manipulation straight-forward whether you want to deal with OS-specific paths (`path/filepath`) or slash-only paths used in URIs (`path`).

> And for interpreting AST, this exists in both Java and C# with different strategies. C# approach is a bit more complex but extremely powerful with build-time source generators that have full access to AST generate new code, fill out existing partial members or intercept calls, and does not require any external scripting. A good example of that is generating gRPC clients and servers code from .proto file by simply executing `dotnet add package Grpc.Tools` and adding .proto reference to .csproj.

gRPC code generation is reading from protobuf descriptors, not modifying existing C# code. It's cool that C# has a good interface for printing C# code, but it's kind of not what I was getting at with that.

And of course, it's obviously still possible to parse the grammar into an AST in Java or C# or C++ or ... but the advantage for Go is that yeah, the grammar is simple and has a lot fewer productions and a lot less syntax than pretty much all of those. That means that mere mortals can write their own refactoring tools, and often do.

With Go's syntax being so dumb, it's possible to just generate proper Go code with text templates, which is what a surprising amount of Go code gen does. It's not especially fragile because the syntax has rather few surprises and once you know them it's not very challenging to follow the rules completely using only simple string operations. (You can also, of course, fill out an AST and write it too, using `go/printer`.)

> Go may seem like a good language after coming from scripting nightmares, it may even seem like a good systems programming language that is easy to use. I promise, it is not. In order to call intrinsics, in C#, I just call them because that's what it offers, in Go, I have to write asm helpers manually.

> If you look at what modern C#, Kotlin and, again, Rust provide in their respective areas, you will soon realize that Go does not have anything to offer that is unique or better, except perhaps the culture of minimalism, which other ecosystems are also advocating for in at least last 5 years.

I disagree. I am not particularly new to programming, and I have come to the conclusion that Go is a great programming language for productivity, as it strikes a nice balance in a lot of aspects of programming language design. I also am not trying to suggest that there are no virtues of C# or Rust, either, just that it's especially weird how much of a hate-boner Go has. It's not like liking it is particularly popular anymore, trust me, as a person that likes Go I would know, so you'd think the irrational hatred of Go would end. Alas, it continues, to the point where there's somehow an argument here that unlike basically every other programming language that has ever existed, somehow Go is the one with zero merits at all. That's pretty much what it feels like I'm arguing against right now, FWIW.

... This comment was too long, so I'm going to need to reply to the rest in a different post ...


> p.s.: I forgot to mention the reason interop was brought up - in C# it can be zero cost or nearly zero cost because it is something that was considered at the language and platform inception. It is one of the reasons C# will never use green threads and eventually will move over upgraded runtime handled task system (mind you, current day state machine implmentation works well, but can be improved). The cost of FFI in Go, unless you use Cgo, is dramatic. This is something that is not acceptable for a language positioning itself as a systems programming one.

The cost of FFI in Go is a cgo callgate regardless of whether you use Cgo, I can point to the actual implementation if need be. The cost from going from Go execution to C execution is ~tens of nanoseconds, so it's not particularly easy to measure. I would guess its on the order of hundreds of CPU cycles. I've stepped through it in IDA from time to time, it's not a ton of instructions. Of course, "not a ton" is a shit load more than "literally zero", but it's worth talking about I think.

There is a potential for greater cost, because with the way the Go runtime scheduler works, if the call doesn't return quickly enough, the thread has to be marked "lost" and another is spawned to take on Goroutine execution. This happens rather quickly of course and it isn't free since it results in an OS thread spawning. But this is actually very important, more on this in a moment...

Meanwhile C# async uses the old async/await mechanism. This is nice of course and it works very well, but it has the problem that execution does not ever yield until you await, and if you DO call a C function and it blocks, unlike Go, another thread does not spawn, that thread is just blocked on C execution until it's over. That was my experience playing with async in .NET 7, but I don't think it can change because either you have zero-cost C FFI or you have usermode scheduling, you can't really get both because the latter requires breaks in the ABI.

I would be happy to talk more because I am honestly pretty disappointed that there's not really a better way to do what Go tries to do. I'd love to have the advantages of Go's usermode scheduling with preemption and integrated GC sequences with somehow-zero-overhead C calls, but it simply can't be done, it's literally not possible. You can take other tradeoffs, but they lose some of the most important advantages Goroutines have over most other greenthread implementations. Google and Microsoft have both produced papers researching this. Microsoft's paper on fibers basically comes to the conclusion that you literally shouldn't bother with usermode scheduling because it's not worth the trouble:

https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2018/p13...

However, their conclusion about the cgo callgate taking around ~130ns does not match what I've seen. But just to be sure, I searched for a random benchmark and found this one:

https://shane.ai/posts/cgo-performance-in-go1.21/

    BenchmarkCgoCall        28711474         38.93 ns/op
    BenchmarkCgoCall-2      60680826         20.30 ns/op
    BenchmarkCgoCall-4      100000000         10.46 ns/op
    BenchmarkCgoCall-8      198091461          6.134 ns/op
    BenchmarkCgoCall-16     248427465          4.949 ns/op
    BenchmarkCgoCall-32     256506208          4.328 ns/op
Of course this may be fairly optimal conditions, maybe it depends on the conditions of the goroutine stack leading up to it, but I think it's fair to say that "less than 50ns per op" is not an unreasonable amount of time for the cgocall to take as long as we're considering that "0ns" is strictly not an option for what Go wants to achieve. With Go you don't have to care if something blocks or not; everything blocks and nothing is ever blocked. That's not something that can be accomplished without some runtime cost. The runtime cost that it actually takes is very nearly zero, but the runtime cost of integrating that with something that doesn't eat that cost is unfortunately higher, and that's where the CGo problem lies.

(I admit that a substantial portion of this problem is actually around the stack pivoting, but if you squint hard enough you can see that this is also inextricably woven into how Goroutines manage to accomplish what they do.)


Wow that's a long post. While I read it, wanted to note that .NET deals with blocked threads by having the threadpool scale the worker thread count dynamically through hill-climbing algorithm that will work to reduce the time the work items wait in their respective queues unhandled (the threadcount can be 1, it can be 200 or more, depending on what you do, 200 is clearly a degenerate case but this is what you get if you managed to abuse it badly enough to act as good old thread per request way). It also has out-of-hill-climbing blocked thread detection (things like Thread.Sleep) to cope with workers being blocked faster. It is all around a very resilient implementation.

As for the cost of FFI, in .NET, the regular p/invokes that don't require marshalling (most of the time it's just UTF-16<->UTF-8) cost approximately ~4-1.5ns. The cost can be further reduced by

- Suppressing GC frame transition (safe for most sub-1ms calls)

- Generating direct P/Invokes when publishing as an AOT binary (they are bound at startup but dynamically linked dependency referenced this way needs to be available)

- Static linking. Yes, .NET's AOT binaries can be statically linked and it is done by system linker, which makes the call a direct jump, which costs as much as a similar call in C. .NET can also produce statically linkable libraries which can be linked into C/C++/Rust binaries (although it can be tricky)

On AST - you are not parsing C# yourself, you are using the same facilities that are utilized by Roslyn. You can do quite a few tricks, I'm working on a UTF-8 string library (which, naturally, outperforms Go implementation :P) and it uses new interceptors API to fold UTF-16->UTF-8 literal conversions during build. My skill is way lower than of engineers working with it in more advanced settings and yet I was able to easily use it - it is very convenient despite the learning curve.

On Go hate - it's simple. It has reached quite some time ago the critical adoption rate where it will be made work in the domains it is applied to regardless of its merits (hello a post on HN describing the woes of a company investing millions in tooling to undo the damage done by bolting in NILs and their unsoudness so tightly). It has serious hype and marketing behind it, because other languages are either perceived as Java-kind-of-uncool, or are not noticed, or bundled, again, with Java, like C#. And developers, who have a rift where their knowledge of asynchronous and concurrent programming should be, stop reading at "async/await means no thread blocky" and never learn to appreciate the power and flexibility task/future-based system gives (and how much less ceremony it needs compared to channels or manually scheduled threads, green or not).

Just look at https://madnight.github.io/githut/#/. Go has won, it pays well, it gets "interesting and novel projects" - it does not need your help. Hating it is correct, because it is both more popular and worse (sometimes catastrophically so) at what other languages do.


Surprisingly, I think we're actually mostly in agreement here, so there's not much to reply to. I think the only real takeaway is that we don't agree on the conclusions to draw.

> On Go hate - it's simple. It has reached quite some time ago the critical adoption rate where it will be made work in the domains it is applied to regardless of its merits (hello a post on HN describing the woes of a company investing millions in tooling to undo the damage done by bolting in NILs and their unsoudness so tightly). It has serious hype and marketing behind it, because other languages are either perceived as Java-kind-of-uncool, or are not noticed, or bundled, again, with Java, like C#. And developers, who have a rift where their knowledge of asynchronous and concurrent programming should be, stop reading at "async/await means no thread blocky" and never learn to appreciate the power and flexibility task/future-based system gives (and how much less ceremony it needs compared to channels or manually scheduled threads, green or not).

I agree that bolting on nil checking to Go is pretty much an admission that the language design has issues. That said, of course it does. You can't eat your cake and have it too, and the Go designers choose to keep the cake more often than not. To properly avoid nil, the Go language would've needed to adopt probably something like sum types and pattern matching. To be honest, that may have been better if they did, but also, it doesn't come at literally no language complexity cost, and the way Go is incredibly careful about that is a major part of what makes it uniquely appealing to begin with.

Meanwhile while Go gets nil checkers, JavaScript gets TypeScript, which I think really puts into perspective how relatively minor the problems Go has actually are.

> Just look at https://madnight.github.io/githut/#/. Go has won, it pays well, it gets "interesting and novel projects" - it does not need your help. Hating it is correct, because it is both more popular and worse (sometimes catastrophically so) at what other languages do.

I gotta say, I basically despise this mentality. This basically reads somewhere along the lines of, "How come Go gets all of the success and attention when other programming languages deserve it more?" To me that just sounds immature. I never thought this way when Go was relatively niche. People certainly use Python, JavaScript, and C++ in cases where they are far from the best tool for the job, but despite all of those languages being vastly more popular than Go, none of them enjoy the reputation of being talked about as the only programming language in history with no redeeming qualities.

People generally use Go (or whatever their favorite programming language is) for things because they know it and feel productive in it, not to spite C# proponents by choosing Go in a use case that C# might do better, or anything like that.

But if you want to think this way, then I can't stop you. I can only hope that some day it is apparent how this is not a very rational or productive approach to programming language debates.

Unfortunately, even though I'm sure it definitely plays no small part, I can't really assume that Go's popularity plays into any person's hatred of it, because flat-out, that would feel like a bad-faith assumption to make...




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

Search: