3 ms·
Yes and no. Let's drill down into this because the details are important. There's a crucial distinction between input and output types in practice. For a given
by howinteresting 6y ago
Yes and no. Let's drill down into this because the details are important.
There's a crucial distinction between input and output types in practice. For a given input type T, Rust makes it possible to abstract over `T`, `&T`, `Cow<'a, T>`, `Arc<T>` etc, by using a trait such as `impl AsRef<T>`.
However, Rust doesn't currently have existential types, so its ability to abstract over output types is more limited. You can implement, for example, `fn foo(&self) -> impl AsRef<T> + '_`, but you can't name that type. So if you want to return an enum, you can't write
```
enum MyEnum {
MyT(impl AsRef<T>),
MyU(impl AsRef<U>),
}
```
Instead, you have to concretize the type somehow, either by boxing things up into a trait object (often but not always possible) or by exposing the generic param:
```
enum MyEnum<RefT, RefU> where RefT: AsRef<T>, MyU: Ref<U> {
MyT(RefT),
MyU(RefU),
}
```
This is a real problem, though one that will be solved through existential types.
> Replacing, say, a concrete type with a trait is about as much work in Rust as it is in Assembly.
I'm not sure what you mean here. I'm not aware of any assembly languages which have traits. Replacing a concrete type with a trait tends to be pretty easy in Rust because mistakes are caught at compile time.
- pron 6y agoI agree that existential types can increase the abstraction level, but not to the level of high-level languages (and they increase generated code-size), because in the end there are still specific low-level details a lot of code needs to care about, like storage and lifetime. > I'm not aware of any assembly languages which have traits. Replacing a concrete type with a trait tends to be pretty easy in Rust because mistakes are caught at compile time. I'm not thinking in terms of language features but abstractions. The best way to see this is to think how many different implementations to a code unit I can do without making the consumer aware? That number is significantly lower for low-level languages compared to high-level languages because things that can be hidden in high-level languages, like layout, storage and lifetime, must not be in low-level ones, hence "low abstraction." Changing something in one place is more likely to require changes elsewhere. Therefore, low-level programs are more rigid, more jigsaw-like, and their evolution more difficult. It is true that a compiler that tells you if you missed a change helps a lot, but it doesn't change the nature of the low-level language, even though it improves its ergonomics (although it's not so simple, as sometimes even correct programs are rejected) -- you still need to do all the extra work, but it doesn't take quite as long.