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

Add maintainable to that list. A program where its developers have a fuzzy idea of ownership of data is not in any way maintainable.


Yep, that's what I meant about "large". If you have a large project, with many developers you're going to want types + generics to maintain it over the many-years and 100,000s to millions of SLOC life.


Rust is hardly the only language to have a type system that supports generics.


I didn't say it was! I said it was an "excellent choice". Right?


Right. But, what I'm saying is, generics does not make Rust unique. There are many other good languages that I think may be a better choice.


This is one of those things that seem plausible, but I have no idea if its really true. I'm not disagreeing, I just can't see it as being obviously true. Can you give me an example of how a fuzzy idea of ownership causes, ideally, a real problem, or a less ideally a simplified example problem? I'm 100% genuinely interested in this.


It's pretty much the reason for segfaults and use-after-free issues (which manifest as either memory corruption or security vulns) in reasonably sized codebases - without a good understanding of ownership, it's non-obvious when a pointer is supposed to become invalid, and if that doesn't match up with when the data is actually freed, you have an issue that's hard to track down later.

If you're using a language with garbage collection, it's obviously not going to result in segfaults, but you can still run into logic errors when part of your code assumes that it's done dealing with a piece of data and another part has a different idea. More generally, if your object is stored in multiple places in your code, you have to remember to clean up all references to it properly, in all the different states your system can be in, and your compiler can't verify you're doing that correctly without a borrow checker.


If you don't understand your object graph, then maintaining a large codebase is going to become very difficult. You'll get questions like 'who is responsible for updating this object' or 'who is responsible for notifying when X happens', or 'why does every object talk to every other object', or 'why does it work very slowly when there's a large number of objects'


Problems involving memory deallocation in the GC applications I've written seem to happen infrequently, certainly infrequently enough that it is one of the lowest items on my list of things I'd like to fix that cause problems in development.

> but you can still run into logic errors when part of your code assumes that it's done dealing with a piece of data and another part has a different idea.

Mostly I think this is sufficiently handled by not mutating shared state as a practice. However, since Rust has mutable borrows, it seems to me that you're still in danger of running into this.


Mutable borrows are not shared - you can't touch the data elsewhere while it's borrowed mutably, and you can't get a mutable borrow while there's immutable borrows. Shared state is unfortunately a common affliction on large codebases, and if the language supports and even encourages it, it can be difficult to prevent it from happening as the codebase grows and customers want features that don't fit into the architecture wonderfully.


In higher-level languages, object lifetime is more than just whether the memory is there or not; it's also about whether the usual invariants apply.

For example, in C#, you need to Dispose() objects that are logically no longer used, to have them properly cleaned up. Using an object after it's disposed typically results in an ObjectDisposedException. This isn't as bad as a segfault, but ultimately it's still a crashing bug in the app - and solving it requires figuring out who needs to call Dispose when - i.e. figuring out the lifetime.


One piece of software that handles a lot of traffic on phone networks has an interesting issue. A bunch of headers are added to a list on every transaction. Most of these header names are constants ("TransactionID", "SourceId", "CallingNumber", etc.). However, they can be dynamic ("x-dynamic-header-foobar"). The easiest way in C to deal with this is just to strdup all the header names, so the final consumer can safely free() them.

End result: This app spends about 30% CPU time on malloc/strdup/free.

In Rust, you simply wouldn't have this design in the first place because it's so easy to avoid. In C, it's super intrusive to fix once it's obvious this is a bottleneck.

Though this isn't necessarily a fuzzy concept of ownership, just more of a pain-to-deal-with thing.


How would rust help in this situation? What alternate design is rust enabling that would be different?


Use an `enum` like Cow[1] that allows passing around static strings along with dynamic strings, as well as interior pointers: the compiler can check that things don't get invalidated and the enum makes it trivial to deallocate things correctly (in fact, it's all done automatically by the compiler), so a more aggressive design can be used, no need to defensively copy the strings.

[1]: https://doc.rust-lang.org/std/borrow/enum.Cow.html


Oh, wow, thanks. I finally understand what the purpose of Cow is!


I can't speak to personal experience since I've only dabbled in Rust, but I have followed it for quite a while and lately I have read more and more how how Rust forces you to structure your data and program in such a way that is more maintainable.




Consider applying for YC's Fall 2026 batch! Applications are open till July 27.

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

Search: