Live data from Hacker News

100 days with Rust: a series of brick walls

brandur.org

121–130 of 323 posts

Re: 100 days with Rust: a series of brick walls

#121
post #38

I am currently learning Rust and I feel this intensely[1]. I really want to like Rust, but I feel like the way they cope with no GC (lifetimes, borrowing) fights me at every turn, and really simple situations in other languages[2] become these intensely painful situations. Every time you think you've worked out how to fix a problem you find while you've fixed that one you've actually created 2 more. Want to have a da…

It's important to note that in C++ you can easily run into problems with what you're describing: structs (objects) with different sizes being put into a vector. You may very well get the program to compile, but then run into odd bugs which come about because your objects get clipped to the size of the smallest possible (the base class). So any overridden methods which expect extra data in a subclass will not behave a…

> It's important to note that in C++ you can easily run into problems with what you're describing: structs (objects) with different sizes being put into a vector.

Baloney. In C++ vector or vector accomplish this task without any problems whatsoever.

Re: 100 days with Rust: a series of brick walls

#122
post #72
post #38

I am currently learning Rust and I feel this intensely[1]. I really want to like Rust, but I feel like the way they cope with no GC (lifetimes, borrowing) fights me at every turn, and really simple situations in other languages[2] become these intensely painful situations. Every time you think you've worked out how to fix a problem you find while you've fixed that one you've actually created 2 more. Want to have a da…

Two things jump out at me: 1. Automatic reference counting is a really good alternative to GC. It takes a little bit more book-keeping, but the performance characteristics are predictable since allocations/frees are handled along the way. Many GC implementations require execution to be halted while the reference graph is traced, which makes it a non-starter for applications trying to deliver predictable real-time per…

> Automatic reference counting is a really good alternative to GC

1) GC is lazy, whereas RC is eager;

2) the use of "pure" RC may lead to memory leaks.

Re: 100 days with Rust: a series of brick walls

#123
post #114
post #75

The problem with Rust is that it is very hard to program interconnected graphs. Basic Rust does not allow cyclic references, which means that almost every graph needs to use special tricks to make it work. These tricks are variants of reference counting. A trick that was copied directly from C++. It feels like having to build a car with only a screwdriver and hammer. Each section of your graph needs to be managed sep…

The easiest way to build graphs in Rust is to store all your graph nodes in a Vec, and use indices instead of references to refer to other nodes. Also a cache locality win.

That is what I concluded too.

And if your nodes can be of different types, you probably need to make them "enums" instead of "objects".

So essentially you need these tricks to work with graphs, which means that your program design is really not as easy as with a garbage collected system, or manual memory management.

I think that many new users have problems with complex graphs in Rust, especially cycled graphs.

Re: 100 days with Rust: a series of brick walls

#124
post #84
post #58

Earlier quoted context omitted.

> Want to have a data structure of variable size (eg a struct with an Vector in it)? You can't do that, structs have to be fixed size. I'm unclear what you mean here, because Vecs in Rust do have a fixed size. You can see this by using std::mem::size_of on a Vec: for any type, a Vec is three words in size. You can see this documented in the stdlib documentation for Vecs: https://doc.rust-lang.org/std/vec/struct.Vec.h…

(Responding to myself to reply to the parent's edit) > You're absolutely right. What I really meant was that you can't have Vec where T is a trait without also wrapping that in a box, which for me in turn doesn't work for a bunch of other reasons. Ah, it sounds like you're using traits as types directly, which is very much discouraged by Rust ( especially in conjunction with taking references to those traits). What t…

> Ah, it sounds like you're using traits as types directly, which is very much discouraged by Rust (especially in conjunction with taking references to those traits). What the language really prefers for you to do is to use traits as bounds on generic types

Can you write an example?

Re: 100 days with Rust: a series of brick walls

#125
post #10

As someone who has been programming in Rust for nearly a year, even for commercial purposes, this article is baffling to me. I've found the compiler messages to be succinct and helpful. The package system is wonderful. It's dead easy to get something off the ground quickly. All it took was learning how and when to borrow.

> As someone who has been programming in Rust for nearly a year, even for commercial purposes, this article is baffling to me.

The author introduces himself as having a Python background, and as someone who experienced some challenges wrapping his mind around SQL. I wouldn't expect anything different.

Re: 100 days with Rust: a series of brick walls

#126
post #113

Earlier quoted context omitted.

I didn't really want to get into the nitty gritty because it detracts from the point (I considered not having the rant paragraph at all for fear that it would just be deconstructed and the exact examples becoming the focus of what I said and not what I was actually trying to say). But anyway!: https://doc.rust-lang.org/error-index.html#E0038 . The one that screws me is the first one, requiring Sized.

I can agree with the initial frustration coming from a GC-ed language until one figures out the right way to design code and structure data in a language with manual memory management. But I got over it eventually. I'm also curious about this nitty gritty bit. I see this: Generally, Self : Sized is used to indicate that the trait should not be used as a trait object. If the trait comes from your own crate, consider r…

Yeah. So I'm following a ray tracing book that uses C++ as example code, and am using Traits as a form of interface: there is a trait of Material that has a function on it, and then there are different "implementations" of Material with different implementations of that fn, and can have arbitrary data stored against them.

I need to have them sized because I need to copy them at a point where I only understand they are a Material and not what the actual struct are, and I need to do this because I can't get a reference to work in this instance due to the fun of lifetimes.

AFAICT the way to do this without Traits in Rust would be to have an enum, and then have an external function that takes the enum, matches against it and runs different code depending.

To me the second one is kind of gross, but I may just go with it, or just give up and do something else.

Re: 100 days with Rust: a series of brick walls

#127
post #38

I am currently learning Rust and I feel this intensely[1]. I really want to like Rust, but I feel like the way they cope with no GC (lifetimes, borrowing) fights me at every turn, and really simple situations in other languages[2] become these intensely painful situations. Every time you think you've worked out how to fix a problem you find while you've fixed that one you've actually created 2 more. Want to have a da…

It's important to note that in C++ you can easily run into problems with what you're describing: structs (objects) with different sizes being put into a vector. You may very well get the program to compile, but then run into odd bugs which come about because your objects get clipped to the size of the smallest possible (the base class). So any overridden methods which expect extra data in a subclass will not behave a…

> It's important to note that in C++ you can easily run into problems with what you're describing: structs (objects) with different sizes being put into a vector.

This is simply wrong.

> You may very well get the program to compile, but then run into odd bugs which come about because your objects get clipped to the size of the smallest possible (the base class).

That has nothing to do with object sizes. You're describing the object slicing problem

https://en.wikipedia.org/wiki/Object_slicing

The cause of this problem is ignorance and incompetence regarding fundamental aspects of the language.

Re: 100 days with Rust: a series of brick walls

#128
post #116

Earlier quoted context omitted.

> What the language really prefers for you to do is to use traits as bounds on generic types to get rid of the dynamic dispatch and the consequent complications with lifetimes Isn't this basically equivalent to only using templates in C++ code ? and doesn't it kill build times & prevent reusability across different shared objects ?

Dynamic dispatch will surely always be faster to compile than static dispatch, but static dispatch has crucial runtime performance advantages (e.g. it enables inlining, which is the ultimate meta-optimization). And extreme runtime performance is one of Rust's raisons d'etre. Having fast compilation is surely a worthwhile goal, but, for Rust, not if it comes at the expense of runtime performance. What do you mean by "…

> What do you mean by "prevent reusability"?

I read that as being about reusing the implementation - the actual machine code bytes which encode a function. If i call a function in library which uses dynamic dispatch, the compiler just emits a few instructions to jump to an existing implementation in the library. If i call a function in a library which uses static dispatch, the compiler will include the relevant monomorphisation of the function, and any other generic functions it calls.

Re: 100 days with Rust: a series of brick walls

#129
post #10

As someone who has been programming in Rust for nearly a year, even for commercial purposes, this article is baffling to me. I've found the compiler messages to be succinct and helpful. The package system is wonderful. It's dead easy to get something off the ground quickly. All it took was learning how and when to borrow.

I can see where the author comes from. I've been working with ^W^W fighting against Tokio this week, and the error messages are horrible. Representative example: error[E0271]: type mismatch resolving ` + std::marker::Send>, [closure@src/server/mod.rs:59:18: 59:74]>, [closure@src/server/mod.rs:60:19: 69:10 next_connection_id:_], std::result::Result >, futures::MapErr , [closure@src/server/mod.rs:74:18: 74:74]>>, std::…

That is rough, but after looking at C++ template error messages a lot recently, that error message looks pretty sweet!

Re: 100 days with Rust: a series of brick walls

#130

Earlier quoted context omitted.

It's important to note that in C++ you can easily run into problems with what you're describing: structs (objects) with different sizes being put into a vector. You may very well get the program to compile, but then run into odd bugs which come about because your objects get clipped to the size of the smallest possible (the base class). So any overridden methods which expect extra data in a subclass will not behave a…

> It's important to note that in C++ you can easily run into problems with what you're describing: structs (objects) with different sizes being put into a vector. This is simply wrong. > You may very well get the program to compile, but then run into odd bugs which come about because your objects get clipped to the size of the smallest possible (the base class). That has nothing to do with object sizes. You're descri…

> The cause of this problem is ignorance and incompetence regarding fundamental aspects of the language.

No! You can rationalize any language problem away with this argument. That's why it's a fallacy with a name: "no true Scotsman" (as in: "no true C++ programmer would let object slicing introduce a bug").

Object slicing is a problem with C++, period.

Post reply on HN