7 ms·
"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 t
by sanxiyn 7y ago
"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!
- apta 7y agoAnother 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.
- sanxiyn 7y agoShared 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!
- reificator 7y ago> 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.
- bcrosby95 7y agoI would describe Rust more like a read-write lock than not sharing.
- nine_k 7y agoA 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.
- pmezard 7y agoCannot wait for "Uber Rust Style Guide".
- badrequest 7y agoYou might be waiting a while, there are zero Rust repositories in their open source repertoire: https://github.com/uber https://github.com/uber
- nicklauri 7y agoI 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.
- skybrian 7y agoYes, 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.
- sanxiyn 7y agoIt apparently comes up often enough to be in Uber Go Style Guide.
- theflyinghorse 7y agoI think the author are just being thorough
- DougBTX 7y ago> 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.
- morelisp 7y agoI 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.
- deleted 7y ago[deleted]
- blub 7y agoIt 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.
- twic 7y agoNo, the point of this observation is that Go exposes this complexity, it just doesn't make it explicit.
- dpc_pw 7y agoExactly. 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.
- weberc2 7y agoMost 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.
- sanxiyn 7y agoHow 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.
- weberc2 7y agoOwnership is different than mutability. Yes, immutability would prevent those errors.
- tapirl 7y agoIt 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.
- sansnomme 7y agoYou 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.
- TheDong 7y agoIf 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.
- sanxiyn 7y agohttps://github.com/thepowersgang/mrustc https://github.com/thepowersgang/mrustc is a Rust compiler without borrow checker.