News for hackers. Stuff that matters.
Re:Go: What We Got Right, What We Got Wrong by cangeroo on Thursday January 04, 2024 @06:01PM (#38873511)
(rant)

That's nice, but also rather self-congratulatory. I was expecting some kind of acknowledgment of the deeper issues in the language. But perhaps that's the central issue, that the language is perfect in their eyes. I'm the problem.

Well, okay then.

I can't recommend the language, because of its type system, the error handling, the unsafe concurrency, the simplistic syntax, nil, default zero, and a large number of mainstream packages are abandoned.

I now use Rust as my main language. It has a flourishing ecosystem and is visionary in so many ways that Go is not.

Put more pointedly, I'm sure Go had its day, when it was competing with PHP as a backend language.

Re:Go: What We Got Right, What We Got Wrong by zik on Thursday January 04, 2024 @07:43PM (#38874260)
I don't think this comment really contributes to the discussion. It comes across as Rust advocacy without having any tangible points to make.

First paragraph: "I don't like it". Second paragraph: snide comment. Third paragraph: "I don't like it". Fourth paragraph: "Rust is better". Fifth paragraph: snide comment.

Re:Go: What We Got Right, What We Got Wrong by ncruces on Thursday January 04, 2024 @08:56PM (#38874800)
There's one thing in there worth discussing IMO: the focus on zero values (incl. nil).

That's the Go mistake, the one that causes most of the issues for the intended audience, the one that can't really be fixed. It's a shame Pike doesn't really discuss this, even if it's hopeless now.

The rest is just people projecting and self-selecting outside of the intended audience. Don't like it, don't use it, we don't all need to agree with you.

Re:Go: What We Got Right, What We Got Wrong by campbel on Thursday January 04, 2024 @11:53PM (#38875827)
Zero values are fine, some benefits, some drawbacks. Workarounds exist for when you need to identify the difference between unset and zero.
Re:Go: What We Got Right, What We Got Wrong by FridgeSeal on Friday January 05, 2024 @03:08AM (#38876855)
No they’re not, they’re a horrible decision, and some of the “solutions” I’ve seen for working around them are band-aid-code at best.

The design decisions around zero values infect protobufs too, and they suck to work around. The fact that an empty message can successfully deserialise into any valid protobuf is an insane decision and should have been thrown out long ago.

Re:Go: What We Got Right, What We Got Wrong by znkr on Friday January 05, 2024 @04:55AM (#38877375)
> The fact that an empty message can successfully deserialise into any valid protobuf is an insane decision and should have been thrown out long ago

The reason for this is that the protobuf wire format is designed for very high entropy: It contains only a minimal amount of metadata and consists mostly of data. This means you can deserialize most wire messages as a different message. This is a tradeoff: smaller message size for loss of schema information. This just means that schemas need to be handled at a higher level. This tradeoff makes some sense if you process millions of protos per second.

BTW: Dismissing a tradeoff like this as insane is derogatory. You can do better

Re:Go: What We Got Right, What We Got Wrong by campbel on Friday January 05, 2024 @01:54PM (#38883034)
This is the main drawback I also experience with zero values, knowing whether something was set or its the zero value. Like I said, there are some work arounds, buts its a tradeoff. Perhaps its a tradeoff you don't like.
Re:Go: What We Got Right, What We Got Wrong by euroderf on Friday January 05, 2024 @04:19AM (#38877201)
> when you need to identify the difference between unset and zero.

Use pointer variables ? Works 4 me.

Re:Go: What We Got Right, What We Got Wrong by campbel on Friday January 05, 2024 @01:55PM (#38883046)
Also what I do. You could theoretically also create your own type that manages deserialization and includes an "is_set" field.
Re:Go: What We Got Right, What We Got Wrong by euroderf on Saturday January 06, 2024 @03:37AM (#38889682)
FWIW: calling Error() on a nil error is an obnoxious NPE fail, so I made this: https://pkg.go.dev/github.com/fbaube/miscutils#Errer
Re:Go: What We Got Right, What We Got Wrong by orangeboats on Friday January 05, 2024 @04:34AM (#38877269)
I don't see how they are fine, when NULL is widely known (even though it might not be agreed by some) as the billion-dollar mistake.

One could have easily added an Optional type that forces programmers to check for nil every time the optional variable is accessed.

Re:Go: What We Got Right, What We Got Wrong by campbel on Friday January 05, 2024 @01:58PM (#38883107)
Couldn't we do an optional type with the type system as is rather than embedding in the language?

type Optional[V any] struct { IsSet bool Value V }

Re:Go: What We Got Right, What We Got Wrong by kaba0 on Friday January 05, 2024 @04:09PM (#38884979)
The type system would store it at compile time, while your type would only have it at runtime.
Re:Go: What We Got Right, What We Got Wrong by ncruces on Friday January 05, 2024 @04:48PM (#38885426)
How does that prevent an unset Value from being used?
Re:Go: What We Got Right, What We Got Wrong by ncruces on Friday January 05, 2024 @07:22AM (#38878367)
Sorry, but no.

Interfaces and how they ended up limiting generics (parametric polymorphism) are a tradeoff. Structural interfaces (duck-typed in an otherwise static-typed, with composition-over-inheritance, language) are innovative, interesting, and offer many benefits, enough to compensate any drawbacks. This is mentioned in the talk.

But the fact that anyone can just conjure a zero value out of thin air, and this fine because it's zero initialized (a decade after Java had proved this was really not good enough) it's pretty inexcusable. And this is not just a "default," it's actually impossible by design to enforce initialization in any way.

Then they did this in a language with pointers, which by necessity are zero initialized to nil, and simply added some timid steps to make nils more useable/useful (like nil receivers being valid). Which unfortunately, in the end, only further complicates static analysis and tooling that might ameliorate the issue.

Finally, if this wasn't enough of a problem, nil panics (any panics, in fact) are a hard crash if a goroutine doesn't handle them, and: it's impossible to add a global handler, it's impossible to prevent goroutines from being created that don't handle panics. So any code that you call can crash your program, and this is considered good form.

If you really feel that zero values are useful enough to justify all this, please explain. Because I just don't see it. This isn't a widely innovative feature that shapes idiomatic programming in an amazing way. The standard library is full of awkward hacks to make zero values useful (esp. in the face of backwards compatibility), where simple enforced construction would be much better.

I love Go. It's my favourite programming tool. I wish I could use it more professionally. But not acknowledging this error, or being dismissive, and doing nothing about it, helps no one.

Re:Go: What We Got Right, What We Got Wrong by campbel on Friday January 05, 2024 @01:53PM (#38883007)
I like zero values because when I create a struct I can know for certain accessing a non pointer won't crash the program. That's a pretty good value add. My type system also knows this, so I don't have to worry about asserting non nil values or adding needless if value == nil checks.
Re:Go: What We Got Right, What We Got Wrong by Gadiguibou on Saturday January 06, 2024 @11:16PM (#38898379)
I understand that you like zero values as an alternative to initialization of objects as nil like Java does it. I think the parent comment explains pretty well what the issues with this approach are. Taking Rust as an example (because that's what I'm most familiar with), it's possible to simply enforce that variables are initialized explicitly or that safe constructors are provided, avoiding all the nil safety issues.
Re:Go: What We Got Right, What We Got Wrong by cangeroo on Friday January 05, 2024 @06:45AM (#38878127)
I was trying to say that:

by paragraph:

1) The article should have acknowledged the issues that a wide part of the community are experiencing.

2) I accept that I'm the problem. But then I must leave.

3) The consequence of their attitude is that I cannot recommend the language anymore. I used to be excited about it, and that disappointment makes me angry.

4) If only Go was trying to be better. Rust is just an example of the visionary leadership that I expect from Go. I want go to be visionary! Because they have some things right, like fast compiliation, cross compilation, simple syntax, and a focus on simple concurrency. But it's like those ideas never developed.

5) Rust is a counterexample, that a language can be visionary, without giving up on its fundamentals.

6) Acknowledgment that Go was the best solution at a time. But also that the time seems to have passed.

Re:Go: What We Got Right, What We Got Wrong by satvikpendem on Thursday January 04, 2024 @09:06PM (#38874864)
I agree, I've used Go before I learned Rust and seeing the differences really changed my mind. I used to use OCaml before so I understood the value of Option and Result types over try/catch and `nil`, but I used Go because it was easy. However, that easiness comes at a cost, namely maintenance over time. You want to get it right the first time around and not have to face challenges later on.

Not to be flippant, but I've often heard Go described as taking the programming language advances over the last 50 years and throwing them away.

Re:Go: What We Got Right, What We Got Wrong by bb88 on Thursday January 04, 2024 @11:38PM (#38875732)
> but I've often heard Go described as taking the programming language advances over the last 50 years and throwing them away.

That's by design, right? Go is very opinionated. They looked at other languages that they hated, e.g., C++/Java and didn't want to replicate them. But then adding their own mistakes along the way.

The brand new mistake that surprised me was that nil does not always equal nil. So just checking for nil is not enough sometimes, one has to "cast" as nil to the type you're expecting. And goland doesn't catch it. C++/Java/Python/C, null always equals null. But not in golang. shrug

The primary issue I have is that go doesn't make it very easy to write unit tests. You have to use interfaces everywhere just to inject your mocks.

I feel like that's the big mistake they made. Any new language needs to make it super easy to write unit tests without forcing major design decisions that affects development.

Re:Go: What We Got Right, What We Got Wrong by earthboundkid on Friday January 05, 2024 @12:50AM (#38876134)
I’ve never seen a real bug from the interface nil != concrete nil thing. When does it come up?
Re:Go: What We Got Right, What We Got Wrong by lenkite on Friday January 05, 2024 @01:24AM (#38876342)
People have raised dozens of issues on the Go tracker because they got stumped by this. You don't really need to look hard on a search engine to see thousands of questions/issues.

If you don't believe me, take a project like k8s and starting from its inception, you can see dozens of issues where people have to explain function returns a nil interface and not a nil value. This is explained a stupendous number of times.

Now repeat this for thousands of Go projects.

Of-course you can claim this is not an issue in the same way that anyone can claim that buffer overflows are not an issue in C/C++ for "real" programmers.

Re:Go: What We Got Right, What We Got Wrong by earthboundkid on Friday January 05, 2024 @10:23AM (#38879978)
I see people say that they're confused by it a lot, sure. But do the bugs get to production? That was my question. Buffer overflows get to production all the time! But do the concrete vs interface nils get to production or are they caught in dev and then someone opens an issue to ask why it doesn't work? I suspect it's more the later.

Obviously, it would be better if Go didn't have this problem. If I made Go 2, it would have blank interface be "none" and blank pointer be "null". Even better, I would add a reference type that can't be null and sum types or something like that. But these things are all relative.

In Python, people using "is" for numbers is a problem. But in practice only very junior developers do that and it mostly gets caught in dev. There was the Digg outage caused by a default argument being [] instead of None https://lethain.com/digg-v4/ and that I see as a slightly more serious bug that can slip by without good code review.

Every language has pitfalls and the question is whether they outweigh the other benefits.

Re:Go: What We Got Right, What We Got Wrong by bb88 on Friday January 05, 2024 @01:39PM (#38882801)
> But do the bugs get to production? That was my question.

Yes, in my case anyway. That code didn't have any unit tests around it. Goland didn't flag it. It's a pattern that was "surprising" to me at least. Particularly since it breaks with tradition.

I consider Goland to be invaluable when coding go. But still, it's not perfect.

> There was the Digg outage caused by a default argument being [] instead of None

FWIW Pycharm flags this now, and can fix this automatically. Not sure about VSCode.

I guess the point I'm making is IDE's should find the novice mistakes, and then a lot of my complaints about languages go away.

Re:Go: What We Got Right, What We Got Wrong by FridgeSeal on Friday January 05, 2024 @03:10AM (#38876860)
> That's by design, right? Go is very opinionated. They looked at other languages that they hated, e.g., C++/Java and didn't want to replicate them.

It’s a pity there’s no other languages in the world that they could have taken good design from, rather than looking at a handful of languages they didn’t like and basically throwing the baby out with the bath water.

Re:Go: What We Got Right, What We Got Wrong by bb88 on Friday January 05, 2024 @01:51PM (#38882971)
I've always thought the best languages were just a step up from another language.

C with garbage collection that compiled natively and had a sane FFI to C would be a good addition. Add a decent library to get work done quickly and you've got a great solution.

That's what it felt like golang was trying to do. I do think it's easier to pick up than C. But it's not something I would say, you must write your code in.

Re:Go: What We Got Right, What We Got Wrong by didntcheck on Friday January 05, 2024 @05:10AM (#38877464)
Yep. Every now and again I look into contemporary Go and try to give it the benefit of the doubt, but it just looks like intentionally going back to Java 5 [1] and touting the lack of features as a feature. What I find surprising is its apparent popularity among people who also like languages like Typescript and Kotlin, which go in the opposite direction, with high expressibility

To be more controversial, its flaws remind me of COBOL, both in the flawed belief that a lack of expressive power makes your programs easier, rather then harder, to read, and in the sense that both languages seemed completely ignorant of any programming language design ideas outside of their bubble, and just stayed stuck in the past

[1] As of 2022. Prior to that it famously didn't even have generics

Re:Go: What We Got Right, What We Got Wrong by demizer on Thursday January 04, 2024 @09:27PM (#38874988)
All these plan9 scientists love their own brand. I started using Go in 2012, but after they killed deps.dev I gave it up. Some years later when I wanted to get work done at work I tried to introduce it on my team and another engineer spent a good amount of time looking into the language and listed all the reasons why it sucked, and he was right. The main takeaway was, yeah it's simple, but it does silly things that makes it a pain to use (error handling and unused imports) to name a few. I personally like the error handling but hated the type system.
Re:Go: What We Got Right, What We Got Wrong by cwbriscoe on Thursday January 04, 2024 @10:08PM (#38875264)
Just run goimports on save then there would be no issue with unused imports. I would take go's error handling over try/catch any day of the week.
Re:Go: What We Got Right, What We Got Wrong by cangeroo on Friday January 05, 2024 @06:33AM (#38878032)
You then have to reimport. Every time when you comment out code.

I guess the compiler authors don't comment out code?

And it's intentionally not optional on the compiler.

So you have to modify the source and compile your own compiler to disable it. It's ridiculously sadistic to their users.

Re:Go: What We Got Right, What We Got Wrong by scns on Friday January 05, 2024 @07:31AM (#38878434)
Is it possible to comment out the imports?
Re:Go: What We Got Right, What We Got Wrong by cwbriscoe on Friday January 05, 2024 @10:13AM (#38879886)
If you use goimports (which also runs gofmt) after commenting out code, you just have to save your file and it will remove any unused imports. There is no reason to go to the extreme extent of compiling your own modified version of go just for this. The tooling is already there.
Re:Go: What We Got Right, What We Got Wrong by alainx277 on Friday January 05, 2024 @08:26PM (#38887358)
The OP mentions that the reimport is the problem (in response to your tooling suggestion). If you comment out code while testing the imports are auto-removed. When you uncomment you need add the correct imports again.
Re:Go: What We Got Right, What We Got Wrong by cwbriscoe on Saturday January 06, 2024 @01:50PM (#38894061)
goimports re-adds them when you uncomment the code. Unless it is ambiguous on which lib to import which doesn't happen very often.
Re:Go: What We Got Right, What We Got Wrong by cangeroo on Saturday January 06, 2024 @04:28AM (#38889925)
I might not have used `goimports` before. I read now that it also auto-imports when you uncomment. That's neat, but it could auto-import the wrong thing, and I'm not sure how it would handle conflicts. It still seems worse than just ignoring my unused imports. Unused imports should be more of a linting thing? If the compiler knows its unused, I don't see why it can't just ignore it.
Re:Go: What We Got Right, What We Got Wrong by cwbriscoe on Saturday January 06, 2024 @01:52PM (#38894085)
Yes, it can import the wrong thing (or version) but it doesn't happen that often in my experience. If you use the libraries in other files it can go off of what is already in your go.mod file.
Re:Go: What We Got Right, What We Got Wrong by AnimalMuppet on Thursday January 04, 2024 @10:25PM (#38875353)
I think you're misreading the article. Pike doesn't say that the language is perfect at all. He says that they did better on the community aspects, but they admit the flaws in the language.
Re:Go: What We Got Right, What We Got Wrong by SPBS on Friday January 05, 2024 @01:23AM (#38876338)
> First, what's good and bad in a programming language is largely a matter of opinion rather than fact, despite the certainty with which many people argue about even the most trivial features of Go or any other language.

> Also, there has already been plenty of discussion about things such as where the newlines go, how nil works, using upper case for export, garbage collection, error handling, and so on. There are certainly things to say there, but little that hasn't already been said.

Re:Go: What We Got Right, What We Got Wrong by hardwaregeek on Friday January 05, 2024 @02:49AM (#38876742)
I agree with the programming language sentiments, but in its defense, Go is very much a language for and by people who don't care about programming languages. I mean this in the nicest way. Rob Pike doesn't care that the concurrency is unsafe or that nil is the billion dollar mistake. Neither do most users of Go. Does that make Go a good language? No. But that's besides the point. It's a convenient, good enough language combined with a compelling set of tools that make it easy to use. It's the crocs of programming languages.
Re:Go: What We Got Right, What We Got Wrong by bborud on Friday January 05, 2024 @05:36AM (#38877632)
Well, some of us kind of care, but not enough to pay the price of ending up using a languages where people care more about language design than writing programs. Go is very much a language for getting things done rather than winning beauty contests. And it has proven itself as a productive language.

I've worked with perhaps half a dozen real "language enthusiasts" in my time. People who spend lots of time obsessing over "perfect" language design and non-mainstream languages. People who never stick to a language for more than a year or three, who insist everyone else accommodate their current fascination with some language, and who leave behind codebases full of code that will be hard to maintain because they are a patchwork of languages. Not caring that the organization then has to take the time both train people in thoselanguages and ensure they have enough people experienced with the language to be able to use a portion of their time to train newbies.

On a few occasions I actually researched their job history and found that these people had a tendency to make a lot of noise, but produce very little of consequence. They'd find jobs at the outskirts of projects where it would be easier to indulge in their interests without clashing with the principals. Most of their code would be gone just months after they left the position.

My advice is that if you care about building stuff, don't hire language enthusiasts.

Re:Go: What We Got Right, What We Got Wrong by jtasdlfj234 on Friday January 05, 2024 @09:01AM (#38879113)
Okay, circling back here. So your position is that nil safety would reduce the value of Go's "getting things done"? As someone who uses Go in production, I don't agree at all.
Re:Go: What We Got Right, What We Got Wrong by bborud on Friday January 05, 2024 @10:08AM (#38879818)
No, I'm saying that nil safety is a lower priority for me than overall productivity. If Go had nil safety that would be very nice. But it doesn't. And it doesn't bother me all that much. Go set out to be a practical language for writing servers - not to tick all the boxes.

In the 8 or so years I've used Go for production software, it hasn't actually turned out to be a big problem compared to my experience with C and C++. If it was a huge problem it should have manifested as such. But in my experience, nil errors are extremely rare in our production code.

If this hadn't been the case, we would probably have invested in Rust. But I can't deny that when I look at those of my friends who use Rust, I'm not exactly impressed with what they accomplish. Even a couple of years in, I see them spending a lot of time fighting with the compiler, having to backtrack and re-think what they are doing or, sometimes, having to rewrite/replace code (sometimes third party) that isn't as strict as they wish to be.

Is it worth the extra effort?

That being said, sure, I think Go would be less of a "getting things done" if the maintainers had felt an obligation to add every checklist item to the language from the start. As someone else pointed out, the fact that they had the guts to say no to a bunch of things was a really good thing. Just throwing all your favorite ingredients in the pot and stirring it doesn't guarantee you'll end up with a delicious dinner. There's a lot more to it than that.

Re:Go: What We Got Right, What We Got Wrong by qaq on Friday January 05, 2024 @03:36AM (#38876992)
I am pretty sure Go is not going anywhere. Pretty much anyone can read Go and understand what is going on which is def. not true for Rust. It's very possible that if Mojo pans out it might be the "mass market" lang. that brings a lot of the Rust goodness to the avg. dev.
Re:Go: What We Got Right, What We Got Wrong by blablak on Friday January 12, 2024 @08:44AM (#38967816)
> Pretty much anyone can read Go and understand what is going on which is def. not true for Rust.

Why do you think so?

If you don't know what `defer` execution order is LIFO, you cannot read code with multiple `defer`'s. IMO, Rust just have more things like `defer`

Re:Go: What We Got Right, What We Got Wrong by jonathanstrange on Friday January 05, 2024 @04:22AM (#38877220)
I've learned Rust but Rust's user community makes it impossible for me to like the language. This hasn't changed over the years, if at all it has gotten worse. If I need high integrity and safety, I'll use Ada or even Ada/Spark with formal verification. For anything else, Go leads to much more productivity than Rust.

In my opinion, Rust is a prime example of overengineering (just like C++).

Re:Go: What We Got Right, What We Got Wrong by blablak on Friday January 12, 2024 @08:34AM (#38967721)
What is wrong with Rust's user community?
Re:Go: What We Got Right, What We Got Wrong by wg0 on Friday January 05, 2024 @04:58AM (#38877395)
Not a rhetorical question. Genuine question. I don't know so I'm asking question.

nil/null is really problematic, true. But how languages handle this otherwise? Is it that program must be statically analyzed to ensure that no nil/null path exists or there are other solutions as well?

Would be thankful for any pointers.

Re:Go: What We Got Right, What We Got Wrong by tubthumper8 on Friday January 05, 2024 @06:39AM (#38878080)
The core problem with null/nil in Go (and Java) is that it is not modeled in the type system. In Java, any reference (which is most types) can be secretly null which is not tracked by the compiler. Go one-ups this and has the same concept for pointers but also introduces a second kind of nil (so nil doesn't always equal nil [0]).

All approaches come down to modeling it in the type system instead of it being invisible.

One approach is modeling it as a sum type [1]. A sum type is a type that models when it's one thing OR another thing. Like it's "a OR b". "null OR not null". So a lot of languages have a type called `Maybe<T>` which models it's a "T OR Nothing". Different languages use different names (like `Option` [2]) but it's the same idea. The key is that null is now modeled using normal / non-special / user-defined types so that it's no longer invisible.

Another approach is using so-called "nullable types" and flow typing [3]. For example, `Foo` is a normal type and `Foo?` is a nullable version of `Foo`. You're not allowed to pass a `Foo?` to a function that requires a `Foo` (the other way is fine). When doing a null check, the compiler narrows a `Foo?` to a `Foo` inside the non-null branch of the check. This is one capability of a more general compiler/language technique sometimes referred to as "narrowing" [4] or "static flow analysis" [5]

[0] https://yourbasic.org/golang/gotcha-why-nil-error-not-equal-...

[1] https://en.m.wikipedia.org/wiki/Tagged_union

[2] https://doc.rust-lang.org/std/option/index.html

[3] https://kotlinlang.org/docs/null-safety.html

[4] https://www.typescriptlang.org/docs/handbook/2/narrowing.htm...

[5] https://learn.microsoft.com/en-us/dotnet/csharp/nullable-ref...

Re:Go: What We Got Right, What We Got Wrong by wg0 on Friday January 05, 2024 @10:48AM (#38880295)
Great and articulate explanation! I learned something today. Thank you!