Live data from Hacker News

A Rust shaped hole

mnvr.in

61–70 of 319 posts

Re: A Rust shaped hole

#61
post #38

Earlier quoted context omitted.

> Wow, a lot of stuff in here surprises me. C definitely can/does have spooky at a distance. Just share a pointer to a resource with something else and enjoy the spooky modifications. Changes are local as long as you program that way, but sometimes it can be a bit not-obvious that this is happening. I think the author means that the language constructs themselves have well-defined meanings, not that the semantics don…

Thanks for explaining what you think the author meant; i meant to reiterate that I was trying to actually understand as opposed to argue, but I forgot; I think sometimes "hey I don't get what you're saying because of reasons XYZ..." comes across as "I think you're wrong". Composing monads is another one of those painful parts of haskell. I remember being so frustrated while learning Haskell that there was all of this…

> frequently I could not _do_ a very straightforward thing, because, for example, some function is a fnOnce instead of fnMulti, or the other way around [..] It became clear to me eventually that some very minor changes in requirements could necessitate massive changes in how the whole data model is structured. Maybe eventually I'd get good enough at rust that this wouldn't be a huge issue, but I had no way of seeing how to get to that point from where I was.

I understand your frustration, and Rust does get too low-level sometimes (see https://without.boats/blog/notes-on-a-smaller-rust/). But the semantic difference between FnOnce and Fn is actually important. Fn consumes its environment and makes it unavailable later. This is an important property. When you don't want that, "just" use Fn, wrap everything in an Arc and clone everything (I understand that this is more ceremony than in other languages, and that can be unjustified).

> I really don't get when rust folks claim "memory safety" like this; we've had garbage collection since 1959.

Agree 100%! What Rust actually gives you is predictability, reliability and compile time checks, while still allowing to write relatively ergonomic imperative and "impure" code. And a sane ecosystem of tools that are designed to be reliable and helpful. I'm currently writing a post about this.

It also gives compile-time data race protection, which is still missing from some other memory-safe languages.

> I still wonder if I have really missed out on some benefit from learning to think more about data ownership in programs.

Yeah :) Affine types + RAII (ownership) allow you to express some really cool things, such as "Mutex forces you to lock the mutex before accessing the T and automatically unlocks it when you're done", or "commits and rollbacks destroy the DatabaseTransaction and make it statically impossible to interact with", or "you'll never forget to run cleanup code for objects from external C libraries" (https://www.reddit.com/r/programming/comments/1l1nhwz/why_us...)

Re: A Rust shaped hole

#62

Earlier quoted context omitted.

Thanks for explaining what you think the author meant; i meant to reiterate that I was trying to actually understand as opposed to argue, but I forgot; I think sometimes "hey I don't get what you're saying because of reasons XYZ..." comes across as "I think you're wrong". Composing monads is another one of those painful parts of haskell. I remember being so frustrated while learning Haskell that there was all of this…

> frequently I could not _do_ a very straightforward thing, because, for example, some function is a fnOnce instead of fnMulti, or the other way around [..] It became clear to me eventually that some very minor changes in requirements could necessitate massive changes in how the whole data model is structured. Maybe eventually I'd get good enough at rust that this wouldn't be a huge issue, but I had no way of seeing…

I asked a bad question; what I meant was specifically thinking about ownership in terms of being required everywhere and to manage memory. But there are for sure real benefits I can see for _other_ properties in certain situations, like avoiding data races that might occur in Haskell. GHC added a linear type extension, for that matter (though AFAIK its still not very great to use). But some of that seems distinct from the question "do I benefit in some data modeling way from thinking about the ownership of memory in my program" as opposed to creating/sharing references whenever convenient.

Re: A Rust shaped hole

#63
post #60

Earlier quoted context omitted.

> such programs are often more, not less, sensitive to OS changes. You may be technically correct that they are more sensitive to the kernel interface changes. But the point is that native, static binaries depend only on the kernel interface, while the other programs also depend on the language runtime that's installed on that OS. Typical Python programs even depend on the libraries being installed separately (in sou…

> But the point is that native, static binaries depend only on the kernel interface Many binaries also depend on shared libraries. > while the other programs also depend on the language runtime that's installed on that OS You can (and probably should) embed the runtime and all dependencies in the program (as is easily done in Java). The runtime then makes responding to OS selection/changes easier (e.g. musl vs glibc)…

> Many binaries also depend on shared libraries.

Yeah, and those are also the opposite of "solid" :) That's why I qualified with "static". I'm so glad that Go and Rust promote static linking as the default (ignoring glibc).

> You can (and probably should) embed the runtime and all dependencies in the program (as is easily done in Java).

Congrats to the Java team and users, then. That makes it similar to the Go approach to binaries and the runtime, which I approve

Re: A Rust shaped hole

#64
post #45

Earlier quoted context omitted.

I do not really agree with respect to C. I often have to deal with C code written by unexperienced programmers. It is always relatively easy to refactor it step by step. For C++ this is much more painful because all the tools invented to make the code look concise make it extremely hard to follow and change. From the feature set, I would say that Rust is the same (but I have no experience refactoring Rust code).

In personal experience, the much stronger and composite type model in Rust makes it easier to refactor. Adding features in particular is a breeze and automatically the compiler/language will track for you the places that use only old set of traits. Tooling is still newer though and needs polish. Generic handling is interesting at times and there are related missing features for that in the language, vis a vis special…

I am wondering about this. In C the nice thing is that you usually change things locally. A line of code does not depend on a million other things. I can't quite see how this works in Rust... At least in C++, template, overloading, etc. can make a single line depend on a lot of things.

Re: A Rust shaped hole

#65

Earlier quoted context omitted.

> frequently I could not _do_ a very straightforward thing, because, for example, some function is a fnOnce instead of fnMulti, or the other way around [..] It became clear to me eventually that some very minor changes in requirements could necessitate massive changes in how the whole data model is structured. Maybe eventually I'd get good enough at rust that this wouldn't be a huge issue, but I had no way of seeing…

I asked a bad question; what I meant was specifically thinking about ownership in terms of being required everywhere and to manage memory. But there are for sure real benefits I can see for _other_ properties in certain situations, like avoiding data races that might occur in Haskell. GHC added a linear type extension, for that matter (though AFAIK its still not very great to use). But some of that seems distinct fro…

The deal with strict Rust-style references is that they solve mutable aliasing bugs (data races, iterator invalidation, all kinds of unexpected mutation really). That's the deal with Rust.

The whole "memory management" thing is mostly a historical accident. We could have a "smaller Rust" that auto-boxes values, has a runtime that handles reference cycles for you, and doesn't guarantee anything about the stack vs heap: https://without.boats/blog/notes-on-a-smaller-rust/

Re: A Rust shaped hole

#66
post #33

Earlier quoted context omitted.

Their rubric is literally just 3 items: "native compilation", "abstractions", and "manual memory management". Had they put that little table at the front of the article, there wouldn't even need to be an article: the table basically says "I'm going to use Rust". That's fine!

The author really doesn't want to do manual memory management. The table is there to summarize things discussed, but he never says he wants to do manual memory management. I just went back and checked. If you do find something that indicates that, I'd appreciate you pointing it out to me, because idgi

I read the article twice, but I could also just be wrong; it's not that big a deal.

Re: A Rust shaped hole

#67
post #64

Earlier quoted context omitted.

In personal experience, the much stronger and composite type model in Rust makes it easier to refactor. Adding features in particular is a breeze and automatically the compiler/language will track for you the places that use only old set of traits. Tooling is still newer though and needs polish. Generic handling is interesting at times and there are related missing features for that in the language, vis a vis special…

I am wondering about this. In C the nice thing is that you usually change things locally. A line of code does not depend on a million other things. I can't quite see how this works in Rust... At least in C++, template, overloading, etc. can make a single line depend on a lot of things.

> A line of code does not depend on a million other things.

But it does! To qoute my top-level comment:

> What about about race conditions, null pointers indirectly propagated into functions that don't expect null, aliased pointers indirectly propagated into `restrict` functions, and the other non-local UB causes?

In other words: you set some pointer to NULL, this is OK in that part of your program, but then the value travels across layers, you've skipped a NULL check somewhere in one of those layers, NULL crosses that boundary and causes UB in a function that doesn't expect NULL. And then that UB itself also manifests in weird non-local effects!

Rust fixes this by making nullability (and many other things, such as thread-safety) an explicit type property that's visible and force-checked on every layer.

Although, I agree that things like macros and trait resolution ("overloading") can be sometimes hard to reason about. But this is offset by the fact that they are still deterministic and knowable (albeit complex)

Re: A Rust shaped hole

#68
post #66

Earlier quoted context omitted.

The author really doesn't want to do manual memory management. The table is there to summarize things discussed, but he never says he wants to do manual memory management. I just went back and checked. If you do find something that indicates that, I'd appreciate you pointing it out to me, because idgi

I read the article twice, but I could also just be wrong; it's not that big a deal.

No problem, get some sleep in that case :D

Re: A Rust shaped hole

#69
post #64

Earlier quoted context omitted.

I am wondering about this. In C the nice thing is that you usually change things locally. A line of code does not depend on a million other things. I can't quite see how this works in Rust... At least in C++, template, overloading, etc. can make a single line depend on a lot of things.

> A line of code does not depend on a million other things. But it does! To qoute my top-level comment: > What about about race conditions, null pointers indirectly propagated into functions that don't expect null, aliased pointers indirectly propagated into `restrict` functions, and the other non-local UB causes? In other words: you set some pointer to NULL, this is OK in that part of your program, but then the valu…

This is true to some degree, but not really that much in practice. When refactoring you just add assertions for NULL (and the effect of derefencing a NULL in practice is a trap - that it UB in the spec is completely irrelevant. in fact it helps because it allows compilers to turn it a trap without requiring it on weak platforms). Restrict is certainly dangerous, but also rarely used and a clear warning sign, compare it to "unsafe". The practical issues in C are bounds checking and use-after-free. Bounds checking I usually refactor into safe code quickly. Use-after-free are the one area where Rust has a clear advantage.

Re: A Rust shaped hole

#70
post #60

Earlier quoted context omitted.

> But the point is that native, static binaries depend only on the kernel interface Many binaries also depend on shared libraries. > while the other programs also depend on the language runtime that's installed on that OS You can (and probably should) embed the runtime and all dependencies in the program (as is easily done in Java). The runtime then makes responding to OS selection/changes easier (e.g. musl vs glibc)…

> Many binaries also depend on shared libraries. Yeah, and those are also the opposite of "solid" :) That's why I qualified with "static". I'm so glad that Go and Rust promote static linking as the default (ignoring glibc). > You can (and probably should) embed the runtime and all dependencies in the program (as is easily done in Java). Congrats to the Java team and users, then. That makes it similar to the Go approa…

> Yeah, and those are also the opposite of "solid" :)

So if that's what the author meant by "solid", i.e. few environmental dependencies, then it's not really about "native" or not, but about how the language/runtime is designed. Languages that started out as "scripting" languages often do rely on the environment a lot, but that's not how, say, Java or .NET work.

> I'm so glad that Go and Rust promote static linking as the default (ignoring glibc).

That doesn't work so well (and so usually not done) once you have a GUI, although I guess you consider the GUI to be part of the kernel.

Post reply on HN