[HN Gopher] Rusty ownership and the lifecycle's stone
       ___________________________________________________________________
        
       Rusty ownership and the lifecycle's stone
        
       Author : kapolos
       Score  : 86 points
       Date   : 2022-11-27 12:14 UTC (10 hours ago)
        
 (HTM) web link (blogs.harvard.edu)
 (TXT) w3m dump (blogs.harvard.edu)
        
       | eternalban wrote:
       | That kitty asked for "Pretty, please". Rust may be the wonder
       | language but pretty it ain't.
        
       | mellosouls wrote:
       | (2021) btw in case any subsequent releases have changed anything.
        
       | 29athrowaway wrote:
       | This article is simply impossible to read.
        
         | bornfreddy wrote:
         | Ignoring (or hiding) the images, the explanation is actually
         | the best one I have seen so far and well worth the read. I
         | guess some people like the fun images too. /shrug
        
         | IOT_Apprentice wrote:
         | I found that not to be the case, and that the explanations were
         | clear. I thought the images were contextually amusing. What
         | specifically was problematic for you to read it?
        
         | meindnoch wrote:
         | I never thought I would feel like I'm watching TikTok when
         | reading an article from Harvard, but here we go...
        
       | harikb wrote:
       | Rust fans, when you take a dig at Java or Python, be a bit nice
       | and don't throw numbers without any basis
       | 
       | > Python is two Orders of Magnitude (100x) slower than C.
       | Suddenly, your $3,000 MacBook Pro barely beats an early-1990s-era
       | 386DX computer.
       | 
       | Right under Java logo
       | 
       | > It is not just 60-frames-per-second games that long for high
       | performance. Any CPU-bound or repeated process also requires it
        
         | klysm wrote:
         | You should be able to vaguely claim that Python and Java are
         | inherently slower than Rust/C/Whatever. I agree claiming that
         | it is 100x slower is a bit unfounded, but it's pretty easy to
         | go find existing benchmarks that show results like this.
        
           | kapolos wrote:
           | Yes, it's exactly as you say.
           | 
           | I did search for benchmark comparisons and bumped into one
           | that had 2 orders of magnitude difference.
           | 
           | But naturally, isolated benchmarks can't encapsulate the
           | whole picture because there's a world of difference between
           | testing how fast a loop runs and performance in production.
        
             | codedokode wrote:
             | I guess that arithmetic operations are not very slow in
             | Python, but if you use objects, then Python performs
             | complicated lookups for every field or method access.
        
         | kapolos wrote:
         | If I recall correctly, the first time I used Java it was way
         | back in JDK 1.1. It was amazingly slow. Of course, today's Java
         | is fast enough for its domain, but I still enjoy throwing a jab
         | at it here and there :)
        
         | tln wrote:
         | I think the Java image should be associated the paragraph
         | before...
         | 
         | > In general, the garbage collector is an inefficient beast.
         | 
         | The article has a tongue-in-cheek style, does the author really
         | need to link to Benchmarks Game and CPU benchmarks?? Modern
         | systems are way more than 100x faster than 386DX anyway.
        
         | pflanze wrote:
         | Speaking from my observations:
         | 
         | You can't make typical Python programs two orders of magnitude
         | faster by rewriting them in C, but that's because those use
         | many bits that are already implemented in C (data structure
         | implementations, regex engine, I/O, databases etc.).
         | 
         | If however you would rewrite those bits in Python, which is
         | what OP said ("that Python is now the only legal programming
         | language in the world to code with"), things _would_ become two
         | orders of magnitude slower (when using the current CPython
         | implementation to run the Python program)! A program doing low-
         | level work (e.g. a B-tree implementation) is that much faster
         | when written in C over Python (if you don 't cheat and write
         | bits of your Python program in C), assuming that the C program
         | does take advantage of the optimizations that you _can_ do (and
         | typically do) in C. It might be more like a factor of 60, but
         | on a logarithmic scale that 's much closer to two magnitudes
         | than one.
         | 
         | This is assuming CPython, not PyPy or one of the subset-of-
         | Python compilers that work more like C.
         | 
         | PS. OTOH, I think a 386DX is more like 1/1000 of a modern CPU's
         | speed (maybe 1/10000 if counting multiple cores and SIMD).
        
       | codedokode wrote:
       | > The biggest of said problems is that the garbage collector has
       | the annoying habit to "pause the world".
       | 
       | I think that main problem of garbage-collected programs is that
       | they usually allocate several times more RAM than they use. This
       | causes excessive swapping which produces more noticeable lags
       | than just garbage collection. I vaguely remember reading
       | somewhere that the difference can be 6x, but I am not sure if
       | this is the correct number. This means that garbage-collected
       | software is great for large expensive servers stuffed with RAM
       | sticks but not so great for a personal computer having just 4 or
       | 2 Gb.
        
         | ok123456 wrote:
         | Go solved this problem with a three color garbage collector.
        
       | nayuki wrote:
       | "Mob program" made me giggle. It must be the logical extension to
       | pair programming.
        
         | asplake wrote:
         | https://en.wikipedia.org/wiki/Mob_programming
        
       | Mxrtxn wrote:
       | Best explanation I have ever heard! Really good examples. Hope to
       | see more.
        
       | timakro wrote:
       | Small correction: contrary to what the post claims this does not
       | compile:                   fn main() {             let s =
       | String::from("hello");             foo(s);
       | println!("{}", s);         }              fn foo(le_string:
       | String) -> String {             println!("{}", le_string);
       | le_string         }
       | 
       | This does, which is probably what the author meant:
       | fn main() {             let s = String::from("hello");
       | let s = foo(s);             println!("{}", s);         }
       | fn foo(le_string: String) -> String {             println!("{}",
       | le_string);             le_string         }
       | 
       | Great post!
        
         | kapolos wrote:
         | Indeed, thank you for catching it! I will make an update.
         | 
         | Thanks again!
        
       | kapolos wrote:
       | A tongue-in-cheek exploration of how Rust achieves memory safety
       | & performance, for people interested in Rust coming from high-
       | level (managed) languages.
        
       | protortyp wrote:
       | This is really one of the easiest-to-comprehend articles I have
       | read so far on Rust ownership! I hope they put out more similar
       | content.
        
       | aaa_aaa wrote:
       | Is it too much to ask for an article without memes, jokes and
       | puns?
        
         | fnordpiglet wrote:
         | Wow. Yes, on the internet, it sort of is.
        
         | kapolos wrote:
         | What can I say, I like memes & jokes -\\_(tsu)_/-
         | 
         | On a more serious note, I think lighthearted content is what's
         | needed when it comes to intro stuff. There are no puns in the
         | Rust Book ( https://doc.rust-lang.org/book/ ) ;)
        
           | turtleyacht wrote:
           | The _Head First_ series uses similar techniques to help aid
           | book learning. At least there is precedent :)
        
       | 29athrowaway wrote:
       | "Let's get rusty" on YouTube has a really good intro to Rust,
       | including this topic and others.
       | 
       | Short videos that are simple and go to the point.
        
       | taberiand wrote:
       | There's a lot of talk in general how Rust has a steep learning
       | curve, mainly due to the borrow checker and lifetimes - but is
       | this as hard as it gets?
       | 
       | Everything here seems logical and fairly self-explanatory, the
       | only slightly alien thing is the lifetime annotation.
       | 
       | Are there advanced gotchas that can actually trip up an
       | experienced coder? Are there some aspects of real work that Rust
       | makes difficult, or impossible?
       | 
       | I mostly code in C# (which in my opinion is an excellent and
       | productive ecosystem), but Rust seems to make a promise of
       | providing a greater level of confidence in the code that is very
       | alluring - I'd like to take the plunge, I'm just a bit worried
       | about smashing into any hidden rocks at the deeper end
        
         | ok123456 wrote:
         | The ownership rules make it very difficult to write data
         | structures.
         | 
         | Even the most trivial singly linked lists have caused
         | innumerable blog articles to be penned on how exactly to do
         | that in the most idiomatic Rusty way.
         | 
         | Personally, I don't see any problem with using unsafe Rust in
         | these instances, because linear types are not appropriate model
         | as you don't have a single source and sink.
        
           | tcfhgj wrote:
           | > Even the most trivial singly linked lists....
           | 
           | Well you exactly named the most difficult to handle data
           | structures for Rust.
           | 
           | There are plenty that are easy
        
             | ok123456 wrote:
             | A linked list is the simplest data structure there is.
             | 
             | Is a Red-Black tree simpler than a linked list to implement
             | than a linked list in Rust? What about a Fibonacci heap?
        
               | mtlmtlmtlmtl wrote:
               | I think using data structures as an example is sort of
               | missing the forest for the trees. It's definitely harder
               | to do, but you generally don't need to as there's an
               | excellent standard library and wider ecosystem of
               | libraries that do this for you.
               | 
               | And implementing data structures in any language is hard.
               | It's just a harder thing to do than most things because
               | there's always gonna be a lot of gnarly implementation
               | details and edgecases.
        
               | ok123456 wrote:
               | > implementing data structures in any language is hard.
               | 
               | Why make it harder.
               | 
               | > excellent standard library.
               | 
               | The standard library is intentionally bare-bones. They
               | don't want to maintain libraries in std, and want you to
               | use crates.
               | 
               | > wider ecosystem of libraries
               | 
               | The quality of these is quite poor in a lot of cases.
               | People literally make blog posts into crates.
        
               | mtlmtlmtlmtl wrote:
               | As someone coming from C I find the stdlib is fine. It
               | has all the datastructures you need for the vast majority
               | of code. It doesn't have very domain specific things like
               | the kind of structures a text editor might use, for
               | instance. That's fine.
               | 
               | As for the quality of crates, yes, this is the case in
               | any language. Using a library includes the responsibility
               | of making sure the quality is up to scratch. This is not
               | unique to Rust.
        
               | antonvs wrote:
               | > Why make it harder.
               | 
               | To achieve static memory safety.
               | 
               | If you don't need or want that, you're probably better
               | off sticking to other languages. Although hopefully, not
               | something like C or C++ which the US government now
               | advises against using for security reasons.
        
               | howinteresting wrote:
               | The simplest data structures are pairs (A, B) and
               | Option<T>.
        
               | ok123456 wrote:
               | Wouldn't call those data structures. Those are data
               | types.
        
               | howinteresting wrote:
               | They are structured data. The restriction of the term
               | "data structures" to what's asked in interview puzzles is
               | ridiculous IMHO.
               | 
               | Edit: and even among "interview puzzle data structures",
               | stacks and queues have much simpler semantics than linked
               | lists.
        
           | codedokode wrote:
           | As I understand, in low-level languages the concept of
           | ownership exists anyway, no matter whether the language
           | allows to declare it explicitly or not. Rust just makes you
           | write it out explicitly.
        
             | tmtvl wrote:
             | The only concept of ownership that exists in low level
             | languages is that the kernel owns memory and gives your
             | program a chunk of it. Aside from that I think the closest
             | equivalent concept is the system break, but that just
             | determines where in memory your stack and heap are divided.
        
             | ok123456 wrote:
             | Yes ownership exists, but the semantics of Rust's automatic
             | ownership system are different as they're enforced as a
             | linear type.
        
           | fleventynine wrote:
           | > Even the most trivial singly linked lists....
           | 
           | Uh, a singly linked list is trivial to implement...
           | struct LinkedListNode<T> {         value: T,         next:
           | Option<Box<LinkedListNode<T>>>,       }
           | 
           | Any data structure where chunks of heap memory are owned by a
           | single pointer (red black trees, singly-linked lists,
           | vectors, deques, circular queues, etc) can be represented
           | easily in safe rust.
           | 
           | Implementing a double-linked list is where things get tricky,
           | as the nodes don't have a singular owner.
        
         | kapolos wrote:
         | Imho, Rust is not hard as in "high complexity hard", but it
         | _is_ hard as in  "must practice to get good at".
         | 
         | All the little rules and new concepts add up and in the
         | beginning it can be frustrating to have the compiler
         | complaining. On the plus side, it's like a motorcycle - it
         | doesn't take long to drive it safely & efficiently.
         | 
         | Learning Rust is fun, I wholeheartedly suggest it even if you
         | don't end up using it at work.
        
           | pitaj wrote:
           | I don't think motorcycles are a great analogy. They're way
           | more dangerous for the driver than a car and you have to be
           | constantly vigilant about your surroundings.
        
             | vladvasiliu wrote:
             | Yeah. If you start to get a bit too confident for your
             | level, you'll just get yelled at by the compiler instead of
             | ending up in the ER (if you're still breathing).
             | 
             | But I suppose the analogy is more along the lines of "it
             | can be intimidating at first, but you can quickly figure
             | out how to use it reasonably well".
        
             | kapolos wrote:
             | You are right, I should have found a better one. I was
             | between "bicycle" and "motorcycle" and I felt that bicycle
             | would imply that learning is a breeze, so I went with
             | motorcycle.
        
         | insanitybit wrote:
         | Unless you're doing something tricky, this is basically it. If
         | you want to implement data structures like cyclic graphs or
         | doubly linked lists things could be trickier. Sometimes people
         | struggle with async because they dive right into that early and
         | it can be a bit tricky if you use async + closures and don't
         | know what you're doing.
        
         | howinteresting wrote:
         | The biggest thing for me was not so much the ownership rules
         | themselves but how to design your code structure around them.
        
           | estebank wrote:
           | I think this exactly it: the rules on their own are simple
           | but their implications are far reaching and hard to recognize
           | ahead of time until you practice writing code.
        
         | oxff wrote:
         | Borrow checking (lifetimes and references) are fairly easy for
         | a beginner to Rust to grasp, I think it is basically a meme at
         | this point that this stuff is hard. Entirely different thing if
         | you are making some kind of async library though, that is when
         | you will run into advanced gotchas.
         | 
         | Rather than a nice steep curve, its more like a threshold
         | function.
        
         | mplanchard wrote:
         | I came to rust mostly from higher level languages, and I didn't
         | have as much of a hard time with lifetimes as I did with
         | dynamic dispatch via trait objects. Lifetimes can certainly get
         | hairy, but it's easy to get around them when you're learning by
         | cloning a value, wrapping it in an Arc, or whatever. I have had
         | multiple times where I wanted to use dynamic dispatch and
         | discovered after a few days of work that my idea wouldn't work
         | for one reason or another. Mostly this came down to some
         | limitations on what trait objects can and can't do, but it has
         | mostly ceased to be a problem now that I understand those
         | limitations better.
        
           | KingOfCoders wrote:
           | You didn't have a hard time with the borrow checker because
           | you used the Rust GC? Was that the argument?
           | 
           | Actually I left Rust and moved to Go although I love Rust
           | much more because every struct ended up sprinkled with Arc.
        
           | pclmulqdq wrote:
           | Cloning values and using Arc to wrap structs carry a huge
           | performance costs. It's pretty easy to write correct Rust.
           | It's a lot trickier to write fast Rust.
           | 
           | That's where the learning curve started to get very steep for
           | me.
        
             | fbdab103 wrote:
             | Is the performance difference meaningful? I write Python,
             | so I suspect even poorly ported Rust will outperform
             | artisanally crafted Python.
        
               | pclmulqdq wrote:
               | Yes. Most of the production use cases for Rust are aimed
               | at C, C++, and Go users. In my past experience, even
               | poorly-written Go tends to outperform poorly-written Rust
               | for many tasks, not to mention C or C++.
               | 
               | You're not exactly the target market if you're writing
               | python.
        
               | fbdab103 wrote:
               | But that is kind of my point. There are plenty of reasons
               | to use Rust that have nothing to do with performance. My
               | brief toe-dip into the Rust world loves the static types,
               | good dependency management, and single executable
               | deployment. That it is faster than my standard language
               | is just the cherry on top.
        
               | pclmulqdq wrote:
               | The unfortunate reality for many Rust fans is that a lot
               | of people would prefer to use a less complicated language
               | when performance doesn't matter.
               | 
               | That Rust program you spent a day golfing to make
               | beautiful use of iterators? Your friend wrote it in go in
               | 15 minutes.
               | 
               | They also get static types, good dependency management,
               | and singe executable deployment. Cython + mypy basically
               | gives you that with Python.
        
               | tmtvl wrote:
               | Yeah, but Python is the slowest language ever. I think
               | that a decent language like D or Common Lisp would
               | outperform poorly written Rust, and they're easier to
               | handle.
        
             | estebank wrote:
             | It really depends on what you're building whether that perf
             | cost is problematic or not, and usually it isn't. If 90% of
             | your code is clean Rust and the last 10% outside of the
             | critical path is a straightforward clone or Arc, then I see
             | no reason not to go that way.
        
           | ninkendo wrote:
           | > Mostly this came down to some limitations on what trait
           | objects can and can't do, but it has mostly ceased to be a
           | problem now that I understand those limitations better.
           | 
           | Care to recount what some of those misunderstandings were?
           | I'm casually interested in Rust but only really observe from
           | afar, since most of my day job is Swift. Don't get me wrong,
           | Swift has some odd limitations around protocols (closest
           | equivalent to traits) that may be similar, but I'm curious to
           | see what some common pitfalls may be with Rust traits.
        
         | protortyp wrote:
         | In my experience it just gets really dirty when you want to
         | work on a single data structure (like a vector) in a threaded
         | way.
        
           | insanitybit wrote:
           | Interesting, I feel like "share vector across threads" is an
           | area that rust excels in. There's `split_at_mut` and `rayon`,
           | and now with GATs you should be able to create a lending
           | iterator too.
        
             | protortyp wrote:
             | Hm interesting, I have to look into GATs then. Anyhow it
             | also got easier with scoped threads. But doing it the old
             | way was always a pain point for me.
        
         | loeg wrote:
         | I found a few things a little difficult. First, the compiler is
         | not actually as smart / accepting of valid borrow patterns as
         | should abstractly be possible. Things like borrowing different
         | subfields of a struct in different and nonconflicting ways to
         | different subroutines. This got a lot better in recent memory
         | with non-lexical lifetimes but I think is still a problem.
         | 
         | Two: splitting mut borrows. It's reasonable to take a mut
         | borrow of some resource and divide it into two independent
         | borrows of exclusive components. Think non-overlapping
         | subarrays, or independent struct members. The language does not
         | really provide this for you, but it is safe. (There are some
         | APIs like this but last time I checked they didn't cover all
         | usecases.)
         | 
         | Structs containing a borrow are just weird and annoying to work
         | with. Lifetime parameterization everywhere is verbose and it's
         | difficult to determine where you've made a mistake. The syntax
         | for describing lifetime relationships is non-obvious to me.
        
           | bobbylarrybobby wrote:
           | For someone looking for an example of this, here's a SO post:
           | https://stackoverflow.com/questions/74592882/extend-a-
           | string...
           | 
           | Tl;dr Rust can't distinguish between a `Vec` whose length is
           | mutable (which might need to reallocate) and one whose
           | elements are mutable (which can provide mutable references to
           | its elements but will never have to move them), so it
           | prevents mutation in a case where it would be safe.
        
             | zozbot234 wrote:
             | Isn't the latter just a mutable slice?
        
           | estebank wrote:
           | > There are some APIs like this but last time I checked they
           | didn't cover all usecases.
           | 
           | This refers to[1]                   <&mut
           | [T]>::split_at_mut(usize) -> (&mut [T], &mut [T])`
           | 
           | used as                   let (first_42, rest) =
           | mutable_slice.split_at_mut(42);
           | 
           | but you can see that the inner logic is just a bit of pointer
           | twiddling[2]                       let len = self.len();
           | let ptr = self.as_ptr();                  // SAFETY: Caller
           | has to check that `0 <= mid <= self.len()`             unsafe
           | { (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), len
           | - mid)) }
           | 
           | [1]: https://doc.rust-
           | lang.org/std/primitive.slice.html#method.sp...
           | 
           | [2]: https://doc.rust-
           | lang.org/src/core/slice/mod.rs.html#1641-16...
        
             | loeg wrote:
             | Yes, exactly. I was using this for zero-copy serialization
             | into a buffer. At the time, I don't believe that API had
             | been stabilized yet.
        
               | estebank wrote:
               | That method has been around since 1.0 (as documented in
               | the source code). Were you using Rust before 2015? If so,
               | _a lot_ has changed :)
        
               | loeg wrote:
               | No, post-1.0. I don't remember exactly why I had to roll
               | my own with unsafe, but it was essentially the same
               | thing.
        
         | MuffinFlavored wrote:
         | Having to clone a String every time you send it around is
         | "confusing" if you come from a C char* pointer background.
         | 
         | You can dereference it to &str but I'm pretty sure that
         | introduces weird "lifetime" &'a or whatever errors in most
         | places (when you are first learning to write Rust that is)
         | 
         | same for structs, I typically just derive Clone. Kind of gross
         | but for hobbyist projects where I want to "move fast" (coming
         | from node.js so it's hard to not treat Rust like a "scripting"
         | language), it suffices.
        
         | revskill wrote:
         | Yes, i'm at awe when seeing .to_ref, to_owned,... and a bunch
         | of alien methods, too.
        
         | sidlls wrote:
         | Well, the blog examples are quite trivial.
         | 
         | Take a look at the standard hashmap implementation
         | (https://doc.rust-
         | lang.org/src/std/collections/hash/map.rs.ht...). Notice the
         | lifetime annotations everywhere. This is a relatively basic
         | data structure, but it has a ton of visual noise due to the
         | constraints of the lifetime and borrow model, and programmers
         | must know, understand _and be able to reason about_ these
         | constraints when using this data structure.
         | 
         | Now imagine a case where you need to operate on values with two
         | (or more) different lifetimes (by definition, all must live _at
         | least_ as long as the one with smallest lifetime, but in
         | practice they all can and will have different lifetimes). Now
         | you have ` 'a` _and_ ` 'b` (and perhaps more) everywhere *and*
         | developers must now reason about that. (random example pulled
         | from a popular networking crate: https://github.com/tokio-
         | rs/tokio/blob/718d6ce8cac9f2e081c0a...)
         | 
         | It isn't trivial to pick up from scratch, especially if one
         | comes from a much higher level language (C#, Java, python,
         | etc.). This is true even for people who are very experienced
         | writing high-quality, durable, and safe code in other languages
         | (e.g., C++) without the help of a compiler, because the
         | ownership and lifetime model are both different and compiler-
         | enforced.
        
           | puffoflogic wrote:
           | > Now you have `'a` and `'b` (and perhaps more) everywhere
           | 
           | Only if you're a bad rust programmer. Lifetime variables can
           | and should be a descriptive identifier, just like literally
           | any other variable. Complaining that there's lots of 'a and
           | 'b around is like complaining that your code has lots of x,
           | y, z variables and you can't keep them all straight... It's
           | not a language problem.
        
             | howinteresting wrote:
             | Lifetime variance often makes it so that more descriptive
             | names are misleading.
        
             | sidlls wrote:
             | It's a "problem" in the sense that it's additional syntax
             | with critically important meaning to the understanding of
             | the code. The descriptiveness of the labels may help, but
             | it won't eliminate the additional cognitive overhead
             | required to mentally parse and reason about the code.
        
             | cwzwarich wrote:
             | To be fair to people using 'a/'b-type variables:
             | 
             | 1) They are used pervasively in the standard library and
             | its documentation.
             | 
             | 2) Due to lifetime subtyping and implicit bounds,
             | descriptive names may be inaccurate. For example, if I have
             | an Ast that contains slices with a lifetime of the source
             | code, I might decide to write Ast<'source>. However, what
             | do I do if I then have a reference to such a thing? Do I
             | add another lifetime parameter, e.g. &'ref Ast<'source>? If
             | I am not going to be returning any of the 'source-lifetime
             | slices, this additional parameter may be redundant. In such
             | a case, do I write &'source Ast<'source> or &'ref
             | Ast<'ref>? Both of those names are incorrect. Do I keep
             | around an extra lifetime parameter to get the correct names
             | (and be more future-proof), or do I just suck it up and use
             | 'a?
        
               | fbdab103 wrote:
               | Nearly every Rust tutorial/blog/reference I have come
               | across uses single letter names.
        
               | puffoflogic wrote:
               | This is a non-problem, or at least a non-unique problem.
               | It is the exact same thing as using variables as function
               | parameters. Sometimes what the variable means in one
               | place is different from another place, so... you use
               | different names. This surprises no one except maybe
               | first-time programmers. Sometimes a variable means
               | nothing and we can give it a single-character name, but
               | then we shouldn't have a bunch of them to get confused
               | by.
        
           | [deleted]
        
         | mtlmtlmtlmtl wrote:
         | I think Rust is a lot easier when you already have decent
         | experience with C. In C you have to reason about ownership and
         | lifetimes too, the only difference is it's all implicit.
         | Knowing C also helps you a great deal in the cases where unsafe
         | is either neccessary or just the best solution. Programmers who
         | haven't touched C might be very hesitant to even consider using
         | unsafe.
         | 
         | Other than that, it's been my experience that lifetimes come up
         | very rarely or even never for a large range of programs. But
         | someone coming from Java/C# where almost everything is a
         | reference might struggle more than others because these
         | languages lend themselves to constructing large object graphs
         | that are annoying to do in Rust. You have to take a different
         | approach, keeping object graphiness to a minimum where
         | possible.
        
         | marcosdumay wrote:
         | That is pretty much it; it is way harder to learn to fit
         | withing those constraints than you are assuming; and it has
         | some very unintuitive consequences that won't appear on 99% of
         | your code, but are very hard to deal with on the other 1%.
        
       | pastaguy1 wrote:
       | Would there be any value in a GC'd language where you had the
       | option to explicitly call do_gc_now()? Is this functionality
       | already out there and just not popular? I haven't spent a ton of
       | time in these languages, so forgive the naivety. Again, naively,
       | this seems like it would be a good compromise between what GC
       | offers but near-determinism when you want it.
       | 
       | I guess Rust and C++ also "pause the world", it's just
       | predictable when it happens. It seems kind of arbitrary in some
       | ways, like maybe I don't want the "world pause" at the end of
       | this scope. There are ways around it obviously, but you start
       | language-wrestling at that point.
        
         | eloff wrote:
         | You can often do this, although some runtimes treat it only as
         | a hint and may ignore it (usually what you want). Go has some
         | pretty strong guarantees on how long it will stop the world
         | for, which makes it much less of an issue. But the best pause
         | is still no pause, which means no GC.
        
         | tsimionescu wrote:
         | Virtually all GC languages have this option, but it is rarely
         | better overall than the default algorithm for deciding when to
         | do it.
         | 
         | The biggest problem with GC is that it is often global, and a
         | simple call to invoke the global GC doesn't usually help from a
         | local scope. There are some arena-based allocators (I believe
         | OCaml's GC uses this strategy) where this may be more
         | beneficial.
         | 
         | But the question always looms: if there is not enough memory to
         | serve an allocation invoked from a hot loop, what should the
         | program do?
         | 
         | Note also that in advanced GCs, such as .NET or the JVM, a hot
         | loop that doesn't allocate will often not need to be stopped by
         | the GC at all. There are even GCs (all proprietary as far as I
         | know) that guarantee a fixed pause time, so that they can be
         | used in real-time workloads - Azul's JVM GC has this option for
         | example.
        
         | kapolos wrote:
         | > I guess Rust and C++ also "pause the world"
         | 
         | Rust does not ship a garbage collector with your binary, so
         | there is nothing to pause your code.
         | 
         | When the compiler adds those drop() statements, they just free
         | the respective memory at runtime. There is no need to pause
         | your application to do that.
         | 
         | The garbage collector needs to pause the application because it
         | takes time to calculate in runtime which parts of the
         | application memory are safe to clean. If the application was
         | running in the meantime, there's no guarantee that the blocks
         | it marked as "safe" are actually still so.
        
         | connicpu wrote:
         | "pause the world" usually refers to garbage collectors having
         | to stop all threads, whereas in Rust and C++ allocation/freeing
         | of memory does not have to make any threads other than the
         | current one wait (unless your memory allocator has global locks
         | and multiple threads are trying to use it)
        
         | nicoburns wrote:
         | > Is this functionality already out there and just not popular?
         | 
         | Yep. Node.js has this for instance (you have to enable it with
         | a command line flag, but it's easy enough to do). I imagine
         | most GC languages have a similar option.
        
       | oconnor663 wrote:
       | > Traditionally, you either have to manage the memory yourself (a
       | la C), or pass the burden down to a run-time feature of the
       | language - heroically called "the garbage collector".
       | 
       | I think it's worth mentioning that C++ manages heap memory the
       | same way Rust does, with destructors (Drop, in Rust). The story
       | is a bit complicated with the new/delete operators only being
       | deprecated recently and lots of legacy code sitting around, but
       | vector and string work the same way, and those have been in
       | common use for decades. The difference isn't the memory
       | management strategy itself, but rather that Rust catches all our
       | mistakes when we retain pointers to destroyed values. (Move
       | semantics are also quite different, but that's a separate idea I
       | think.)
        
         | pjmlp wrote:
         | Good luck telling to most enterprise developers that new and
         | delete are deprecated, specially when ISO C++ makes zero
         | reference to it.
        
       ___________________________________________________________________
       (page generated 2022-11-27 23:01 UTC)