| ▲ | Darmani 3 hours ago | |||||||
That "and so on" is doing a lot of work. You may accept rejecting garbage collection as a reasonable trade-off, but the bulk of the cost is coming from a much more aggressive tradeoff Rust is making with is at odds with the goals of most application code. A deeply-baked assumption of Rust is that your memory layout is static. Dynamic memory layout is perfectly compatible with manual memory management, but Rust does not readily support it because of its demands for static memory layout. A very easy place to see this is the difference in decorator types between Rust and other languages like Java. Java's legacy File/reader API has you write things like `new PrintWriter(new BufferedWriter(new FileWriter("foo.txt")))`, where each layer adds some functionality to the base layer. The resulting value has principal type `PrintWriter` and can be used through the `Writer` interface. The equivalent code in Rust would give you a value of type `PrintWriter<BufferedWriter<FileWriter>>` which can only be passed to functions that expect exactly that type and not, say, a `PrintWriter<BufferedWriter<StringStream>>`. You would solve this by using a template function that takes a `T where T: Writer` parameter and gets compiled separately for every use-site, thus contributing to Rust's infamous slow build times. It would be perfectly sane, and desirable for application code, to be able to pass around a PrintWriter value as an owned pointer to a PrintWriter struct which contains an owned pointer to a BufferedWriter struct which contains an owned pointer to a FileWriter struct. You could even have each pointer actually be to a Writer value of unknown size, and thus recover modularity. In Rust, there is sometimes a painful and very fragile way to do this: have each writer type contain a Box<&dyn Writer>, effectively the same as the Java solution above. This works, except that, if one day you want to add a method to the Writer trait that breaks dyn-compatibility, then you will no longer be able to do this, and will need to rewrite all code that uses this type. | ||||||||
| ▲ | mplanchard 34 minutes ago | parent | next [-] | |||||||
You can usually manage dyn compatibility issues in my experience by writing a base trait that is not dyn compatible and then an Ext trait that is, which is auto implemented for all implementers of the base trait. You see this pattern all over the place, including with several of the buffer traits you mentioned. Mostly, this works out well enough: dyn compatibility pretty much just insists your methods can in fact work with just a reference to an unknown variant of the type. | ||||||||
| ||||||||
| ▲ | singpolyma3 14 minutes ago | parent | prev [-] | |||||||
I have to sit with the specific example, but a PrintWriter struct which owns a Box<impl Writer> and has no generics should be quite doable I'd think? | ||||||||
| ||||||||