27 ms·
There's nothing at all preventing you from having a Vec in a struct, and the use cases for variable sized structs are pretty rare. It sounds more like you confl
by physguy1123 9y ago
There's nothing at all preventing you from having a Vec in a struct, and the use cases for variable sized structs are pretty rare. It sounds more like you conflated having a different problem with having a Vec be in a struct and stuff like that poisoned your further attempts to understand the language
- SCdF 9y agoYou're absolutely right. What I really meant was that you can't have Vec<T> 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. In any case, my point remains the same: it is very challenging-- at least for someone used to just creating data structures and letting GC handle it-- to build code that does what you want, and you spend large amounts of time "fighting" the compiler. I am OK if people wish to peg that on me being stupid or whatever, it doesn't change the core point: it's hard for new people to get into, and if you're wanting there to be less Electron apps and more native apps things like Rust being easy to use seems important for that.
- comex 9y agoIt fundamentally doesn't make sense to have a Vec<Trait>, because Vec expects each of its elements to be the same size (otherwise you couldn't index into it in O(1)), but different types that implement Trait can have different sizes. Other languages allow this because they automatically box everything, but Vec<Box<Trait>> should accomplish the same in Rust; I'm curious what the "other reasons" you referred to are, that make that unsuitable. Alternately, if any given instance of the Vec is only expected to have values of a single type (but the type can be different for different Vecs), you may be able to accomplish what you want with generics instead. That said, trait objects in Rust are pretty broken in general, so - this is just speculation, but - I think your problem might actually arise from that, and the Vec<Trait> issue is a red herring.
- SCdF 9y agoI 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 https://doc.rust-lang.org/error-index.html#E0038 <-- these are restrictions on Box<Trait>. The one that screws me is the first one, requiring Sized.
- ehsanu1 9y agoI 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 removing this restriction. I guess you needed that sized restriction for some reason, assuming this was a trait of your own?
- SCdF 9y agoYeah. 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.
- tangent128 9y agoWould it work to add a boxed_clone() function to your Material trait that returns a Box<Material>? (or create a BoxedClone trait if you need that pattern more generally) Implementations of boxed_clone() could still use &self.clone() to limit boilerplate. Alternatively, if the Materials are not going to be modified and you just need multiple references to the same object, you could replace the Box<> with an Rc<> or Arc<>.
- physguy1123 9y ago> In any case, my point remains the same: it is very challenging-- at least for someone used to just creating data structures and letting GC handle it-- to build code that does what you want, and you spend large amounts of time "fighting" the compiler. This is a fundamental problem of languages that don't use a managed runtime. You either take the C route and just hope the user did things right or try and enforce it somehow. If you're used to writing GC-code, your problems around understanding object lifetimes are probably going to manifest as 'fighting the compiler' with Rust whereas with C they would manifest as intermittent and hard-to-track segfaults. If I follow the github in your profile and take the Rust issue you opened, in C that mistake may never manifest except in certain control paths after you've turned off debug mode, and you'd compile code easily but sit banging your head against the wall. I write a decent amount of Rust and write both C and C++ professionally, and in most cases Rust is drastically easier to write nontrivial code in because it catches all sorts of lifetime issues and has so many QOL improvements.