News for hackers. Stuff that matters.
Re:Uber Go Style Guide by sanxiyn on Friday October 11, 2019 @12:20PM (#21225807)
"Copy Slices and Maps at Boundaries. Slices and maps contain pointers to the underlying data so be wary of scenarios when they need to be copied. Keep in mind that users can modify a map or slice you received as an argument if you store a reference to it. Similarly, be wary of user modifications to maps or slices exposing internal state."

This could be used as an ad for Rust borrow checker, verbatim. You can't modify a map or slice you passed as an argument if a reference to it is stored!

Re:Uber Go Style Guide by apta on Friday October 11, 2019 @12:22PM (#21225823)
Another solution is to use immutable and/or persistent data structures. Of course, because golang doesn't have generics, it becomes unwieldy to have a library of them, unlike what we see in Java, Scala, etc. where these enjoy a wider adoption.
Re:Uber Go Style Guide by sanxiyn on Friday October 11, 2019 @12:25PM (#21225860)
Shared mutable state is evil, so "not mutable" has been proposed as a solution. Rust is different, because Rust's solution is "not sharing". You can still mutate!
Re:Uber Go Style Guide by reificator on Friday October 11, 2019 @12:49PM (#21226097)
> Rust is different, because Rust's solution is "not sharing". You can still mutate!

For the record, rust does also default to immutability, and you can share immutable references all you'd like.

Re:Uber Go Style Guide by bcrosby95 on Friday October 11, 2019 @04:21PM (#21228085)
I would describe Rust more like a read-write lock than not sharing.
Re:Uber Go Style Guide by nine_k on Saturday October 12, 2019 @12:25PM (#21234311)
A lock is acquired and detected at runtime.

Ownership and move semantics are checked at compile time, and allow effective "not sharing" without waiting or defensive copies.

Re:Uber Go Style Guide by blub on Friday October 11, 2019 @03:50PM (#21227790)
It could be, if the Rust borrow checker were a Go tool that would solve this problem.

In reality it's part of a different language which exposes a lot of complexity to the programmer as opposed to Go, which religiously avoids that.

Re:Uber Go Style Guide by twic on Friday October 11, 2019 @03:59PM (#21227867)
No, the point of this observation is that Go exposes this complexity, it just doesn't make it explicit.
Re:Uber Go Style Guide by dpc_pw on Friday October 11, 2019 @04:13PM (#21228023)
Exactly. Ownership/lifetimes exist in almost every mainstream PL (anywhere where you can have any sort of references + mutability). It's just people pretend it doesn't, and hope everything is going to be fine. And when you bring it in front of their consciousness they scream in panic, like it didn't exist before. Once you internalize Rust ownership rules, they are almost effortless and you see and obey them in any code in any PL you happen to be programming in.
Re:Uber Go Style Guide by weberc2 on Friday October 11, 2019 @09:18PM (#21229870)
Most languages have a GC so there really is no ownership to pretend away (if you like, everything is owned by the GC). Rust can be super cool without inventing fake problems for other languages.
Re:Uber Go Style Guide by dpc_pw on Saturday October 12, 2019 @12:09AM (#21230612)
I'm sorry, but that is a naive misconception. "everything is owned by the GC" is a sign of not understanding concept of ownership, BTW. GC is not an actor in the system, so does not participate in the ownership. A Java finalizers might kind of do stuff, but that's when all references are gone, so they have exclusive ownership.

Anyway... Languages with GC still do have ownership. It is just defaulting to be the most problematic case of "shared ownership" everywhere. Shared ownership is only worry-free if you don't ever modify data. Which is possible, but actually harder and more constraining to implement in a practical software (especially if you care about any performance). So then you either have to synchronize everything with mutexes, and figure out a way to not deadlock yourself on every step (also hard), or you have to implicitly track ownership and decide who can and when mutate the data, which is exactly what Rust would make you do, but this time you get no compiler help. The only reason people don't notice that is because they do it incorrectly and it works most of the time, so they are unaware.

There is no escape from it - one has to figure out ownership with a GC or without it, because GC has nothing to do with ownership. It only reclaims memory after all references are gone. That's it. That is actually very, very little improvement.

Re:Uber Go Style Guide by blub on Saturday October 12, 2019 @04:15AM (#21231437)
"The only reason people don't notice that is because they do it incorrectly and it works most of the time, so they are unaware."

Ironically, that's Rust biggest problem: not using perfect ownership management works for most software most of the time and that's good enough for most people and companies.

You probably can't sell ownership management as a feature. The only thing that Rust can sell and that makes sense is "it won't crash" + "it's fast", but then there's a lot of other languages that have the first property and the second is not very appreciated, as seen in the rise of so-called Electron apps and web apps in general.

Re:Uber Go Style Guide by dpc_pw on Saturday October 12, 2019 @09:00PM (#21237509)
Sure. SWE is not a first industry where you can get away with cutting corners or straight incompetence. And some people are going to write a code taking care of ownership by experience, skill, etc. and they don't need Rust. They might not know they are taking care of ownership, and yet do it correctly. Rust is only formalizing and verifying it.

I think in time more and more people and teams will discover that doing stuff with Rust is just cheaper and more productive. You learn ownership once, you get great results ever after.

Re:Uber Go Style Guide by weberc2 on Saturday October 12, 2019 @08:10AM (#21232412)
Ok, then educate me—what is ownership if not the responsibility for managing (cleaning up) a resource? In my C and C++ days, I never heard of it refer to some kind of exclusive permission to mutate a resource (which seems to be your meaning), but rather as the responsibility to free the resource (as in “the owner must and only the owner _can_ free the owner resource”).

It seems likely that you and I are using different definitions, and yours Rust-specific (and therefore not meaningfully generalizable to other languages, especially those with GC).

Re:Uber Go Style Guide by twic on Saturday October 12, 2019 @02:54PM (#21235357)
Ownership is (at least) two things: who has the responsibility for destroying an object when it's finished with, which GC takes care of, and who has the right to mutate an object while it's alive, which GC doesn't.

I mostly write Java for a living, have done for a decade, and still occasionally trip myself up by mutating an object I'd forgotten I've shared.

Re:Uber Go Style Guide by steveklabnik on Saturday October 12, 2019 @10:58AM (#21233640)
In Rust, we also say that it’s the right to destroy.
Re:Uber Go Style Guide by weberc2 on Saturday October 12, 2019 @01:14PM (#21234637)
Thanks for responding, Steve. I understand that “ownership” implies the right to destroy in any language. The bit I’m not so clear about is whether or not there are other rights/responsibilities (such as the right to mutate) as the OP suggests and whether a definition that includes those rights/responsibilities can meaningfully apply to any language or just Rust.
Re:Uber Go Style Guide by steveklabnik on Saturday October 12, 2019 @10:22PM (#21237865)
I think they’re talking about the borrow checker, which is technically distinct from ownership.
Re:Uber Go Style Guide by sanxiyn on Friday October 11, 2019 @10:13PM (#21230155)
How is it a fake problem? Uber is copying slices it doesn't need to copy, suffering significant performance penalty, because it is too error prone in Go. Rust completely prevents this error.
Re:Uber Go Style Guide by grumpydba on Saturday October 12, 2019 @01:46AM (#21230946)
It's a trade-off. Programmer's productivity versus theorically perfect ownership handling.

I think that rust fills the needs of applications with extreme requirements. A browser is in that niche. Not all software is.

Thus most of the time you don't have to inflict yourself the pain to work with it.

Re:Uber Go Style Guide by weberc2 on Friday October 11, 2019 @10:34PM (#21230251)
Ownership is different than mutability. Yes, immutability would prevent those errors.
Re:Uber Go Style Guide by rictic on Saturday October 12, 2019 @12:03AM (#21230582)
The point is that ownership also prevents these errors. If there are never two simultaneous mutable references to something, then you can get the advantages of immutable data structures without paying the performance penalty.
Re:Uber Go Style Guide by weberc2 on Sunday October 13, 2019 @09:21AM (#21240213)
We’re having a semantic debate. Ownership appears to mean something different to Rust folks, which is fine. I agree that Rust’s borrow checker (what you appear to be referring to as ownership or the enforcer thereof) prevents errors and is generally very cool. It’s just not what I understand ownership to mean.
Re:Uber Go Style Guide by tptacek on Friday October 11, 2019 @05:29PM (#21228653)
Language fight! Definitely I think that's a good discussion to promote on a thread about _a style guide for a language_!
Re:Uber Go Style Guide by twic on Saturday October 12, 2019 @02:56PM (#21235368)
Language fights are of the things many of us enjoy most about HN. Would you go to a metal show and complain about the moshpit? Just stand safely to one side and enjoy the vibe, man.
Re:Uber Go Style Guide by eternalban on Friday October 11, 2019 @08:01PM (#21229484)
I think this is where Rob Pike got it backwards (in terms of one of his stated goal for Go).

Go is a very effective tool in the hands of experienced programmers, without having to pay the cognitive load price of 'Mommy' languages. I am reminded of Bryan Cantrill's rant regarding threads in this context.

Writing solid software is hard. It takes skill, experience, and serious battle scars. Tools and languages can help, but at the end of the day, it comes down to the team that writes the code.

Re:Uber Go Style Guide by ummonk on Friday October 11, 2019 @10:36PM (#21230258)
Even the most experienced programmer can’t hold all of a million line codebase in his or her head. And that is the issue with a language like Go - you can be careful about the code you write but it doesn’t have static analysis enforceable constraints on code other people write that interacts with your code / data.
Re:Uber Go Style Guide by eternalban on Saturday October 12, 2019 @05:18AM (#21231684)
That is a seriously ridiculous proposition in my opinion. If you find yourself involved in a project that requires you to hold a "million" lines of code in your head, refer to above point I made regarding "team". Something has gone seriously wrong somewhere if that is the situation.

This should not be news to this audience on HN: proper software architecture, design, and development processes trump "language" any day, any time, any planet. Conversely, even the most 'profoundly correct' language in the hands of unprepared development teams can result in software disasters.

The human factor is still paramount in software development. That is my experience after decades in this profession and is not mere conjecture.

Re:Uber Go Style Guide by skybrian on Friday October 11, 2019 @01:37PM (#21226582)
Yes, that's not good, but it seems like in practice this doesn't come up too often in Go?

More typically you're building a new slice containing the results of a query or other computation, and returning it without keeping a reference. Or instead of exposing an internal map, you have a Get method.

Re:Uber Go Style Guide by morelisp on Friday October 11, 2019 @03:17PM (#21227504)
I have found this to be true of everything other than byte slices, where the result is some of the worst bugs I've had the displeasure of tracking down.

Many Go libraries like to offer passing a byte slice to reuse as a destination. Many Go libraries take byte slices or structs containing them as arguments. A common result is "loop over some input, read it into the reusable slice, pass the slice to the next step". It even sort of works - until the next step does something asynchronous.

It doesn't help that:

- Lots of things return a new slice "sometimes" - _this_ append() result is safe to pass on; this other one is not; this other one "it depends".

- The `x[:]` idiom to turn an array into a slice looks exactly like a Python copy, but actually shares the same backing store.

In the end we basically banned reusing slices as a result. (The rule I tell new programmers is "if you pass the slice elsewhere in a loop, the slice needs to be allocated within the loop.") Which is a shame, because the performance gain from safe reuse is often significant. But until the type system blocks us from changes, usually in the oblivious callee, which turn a safe use into an unsafe one, it's simply too much effort to remember and review each case.

Re:Uber Go Style Guide by jimbo1qaz on Friday October 11, 2019 @10:42PM (#21230275)
In Python's Numpy library, `x[:]` also shares the same backing store. This bit me in the ass when I was learning Numpy.
Re:Uber Go Style Guide by skybrian on Friday October 11, 2019 @07:49PM (#21229436)
Ouch. I guess this would be a reason to use strings more, since they're immutable.
Re:Uber Go Style Guide by morelisp on Saturday October 12, 2019 @06:28AM (#21231966)
Someone using a string when they really want a byte array/slice would fail review on its face. Excepting external APIs forcing "strings" on us, we only use the Go string type for UTF-8 code unit sequences (and this is a common assumption in the Go world).
Re:Uber Go Style Guide by sanxiyn on Friday October 11, 2019 @08:01PM (#21229483)
Using string doesn't allow reuse, so you are leaving significant performance on the table.
Re:Uber Go Style Guide by Strom on Friday October 11, 2019 @06:10PM (#21228947)
This issue comes up with a reused bytes.Buffer.

    var buf bytes.Buffer
    buf.WriteString("foo")
    b := buf.Bytes()
    fmt.Printf("b == %v\n", string(b)) // b == foo
    buf.Reset()
    buf.WriteString("bar")
    fmt.Printf("b == %v\n", string(b)) // b == bar
Yes the documentation for .Bytes() says that "The slice is valid for use only until the next buffer modification" but people don't always read the docs for every method they use, especially if it's a method they've used a bunch before. Having a reusable buffer that you return the .Bytes() value from is very tempting. Bug-free code would either copy the result or not reuse the buffer.
Re:Uber Go Style Guide by DougBTX on Friday October 11, 2019 @02:48PM (#21227210)
> but it seems like in practice this doesn't come up too often in Go?

It comes up in any language that allows shared mutable state, so not much in functional languages which discourage mutability or Rust which discourages shared mutability.

On the other hand, most code tries to avoid shared mutable state by convention, there’s a nice bit in the Go lang design article that basically says convention is good enough, significantly simplifies the language, at the cost of the odd bug.

Re:Uber Go Style Guide by sanxiyn on Friday October 11, 2019 @02:04PM (#21226833)
It apparently comes up often enough to be in Uber Go Style Guide.
Re:Uber Go Style Guide by theflyinghorse on Friday October 11, 2019 @02:31PM (#21227061)
I think the author are just being thorough
Re:Uber Go Style Guide by pmezard on Friday October 11, 2019 @01:22PM (#21226453)
Cannot wait for "Uber Rust Style Guide".
Re:Uber Go Style Guide by badrequest on Friday October 11, 2019 @01:52PM (#21226720)
You might be waiting a while, there are zero Rust repositories in their open source repertoire: https://github.com/uber
Re:Uber Go Style Guide by nicklauri on Saturday October 12, 2019 @10:54AM (#21233605)
I would love to see that too, but I think that's likely never happened. Because Rust is kinda hard and takes quite amount of time and money to train new people, add more stacks on maintaining projects, and important thing is that I don't see why they have to use Rust. Go is good enough and they can work around with Go's disavantages.
Re:Uber Go Style Guide by sansnomme on Saturday October 12, 2019 @12:13AM (#21230628)
You can always write a borrow checker for Go and have the lifetime annotated in comments similar to how pre-3.7 Python type checkers worked.

In Rust, the borrow checker is too a separate static analysis stage and not directly tied to code gen. There are Rust compilers without the borrow checker.

Re:Uber Go Style Guide by TheDong on Saturday October 12, 2019 @01:31AM (#21230895)
If you wrote such syntax on top of Go, it would no longer be go, it would be a new language you created.

The go authors wouldn't accept it, the ecosystem wouldn't work with it, and it would be fighting an uphill battle rather than just using rust or building a new language.

> There are Rust compilers without the borrow checker

Then those compilers do not compile rust. They compile a bastardized version of rust whereby programs that are not valid rust programs can compile.

Also, can you name these non-borrowck-ing rust compilers? You say there's multiple, so you should be able to at least name one or two.

Re:Uber Go Style Guide by sanxiyn on Saturday October 12, 2019 @05:44AM (#21231790)
https://github.com/thepowersgang/mrustc is a Rust compiler without borrow checker.
Re:Uber Go Style Guide by tapirl on Friday October 11, 2019 @06:15PM (#21228988)
It is a real need sometimes (many times in fact) in programming. This is one of reasons why Go is so flexible.

You can't have the best of both worlds. You win some and lose some. Rust avoids this but loses flexibility.