Live data from Hacker News

Abstraction without overhead: traits in Rust

blog.rust-lang.org

111–120 of 150 posts

Re: Abstraction without overhead: traits in Rust

#111

Earlier quoted context omitted.

Extra indirection? There is less indirection. With the C++ approach the data is one pointer away but the vtable is two pointers away. With the Rust approach both data and vtable are just one pointer away.

That's assuming that a "full pointer" (i.e. an unpredictable address to an arbitrary point in heap memory) is the only way to get a reference to an object. What about if you want to stick a bunch of objects in a vector, and iterate over them linearly? In the C++ approach, the data will have a nice linear cache access pattern. In the Rust approach (unless I'm missing something) you'd be storing a vector of (double siz…

Since you are talking about a heterogeneous [edit: homogeneous] array, you would store the concrete structs continously in Rust as well. Rust would also not waste space in the vector for storing a vtable-pointer, and would instead construct fat pointers dynamically when needed (since it knows the type, it knows which vtable to inject in the fat pointer).

Re: Abstraction without overhead: traits in Rust

#112

Earlier quoted context omitted.

That's assuming that a "full pointer" (i.e. an unpredictable address to an arbitrary point in heap memory) is the only way to get a reference to an object. What about if you want to stick a bunch of objects in a vector, and iterate over them linearly? In the C++ approach, the data will have a nice linear cache access pattern. In the Rust approach (unless I'm missing something) you'd be storing a vector of (double siz…

Since you are talking about a heterogeneous [edit: homogeneous] array, you would store the concrete structs continously in Rust as well. Rust would also not waste space in the vector for storing a vtable-pointer, and would instead construct fat pointers dynamically when needed (since it knows the type, it knows which vtable to inject in the fat pointer).

> you would store the concrete structs continously in Rust as well. Rust would also not waste space in the vector for storing a vtable-pointer, and would instead construct fat pointers dynamically when needed (since it knows the type, it knows which vtable to inject in the fat pointer).

Uh, what? How is the compiler just supposed to magically know which of the structures in the array are of what type, without any additional identifying information? I'm assuming that in this optimized case, there's a hidden type field in each struct, that it would use to index into a table of vtable pointers? If so, there you go, that's yet another level of indirection.

Re: Abstraction without overhead: traits in Rust

#113

For being a lower level language, Rust's abstractions really make feel closer to a higher level language than to C. It will be even more so if HKT's land.

HKT = Higher-Kinded Polymorphism [1]

[1] http://www.hydrocodedesign.com/2014/04/02/higher-kinded-type...

Re: Abstraction without overhead: traits in Rust

#114
post #99

> What you do use, you couldn’t hand code any better. ... given you have no information about runtime behavior other than the static code. How to achieve "zero-cost abstractions" is, as usual, a design tradeoff. Rust -- like C++ -- lets you choose in your code whether you'd like to pay for an abstraction or not. This does produce good machine code, but has two costs: 1/ the language gets more complicated and the prog…

I wouldn't call that zero-cost. It's more like variable-cost, which could be even worse than always doing virtual calls in some application types.

Re: Abstraction without overhead: traits in Rust

#115

Earlier quoted context omitted.

Since you are talking about a heterogeneous [edit: homogeneous] array, you would store the concrete structs continously in Rust as well. Rust would also not waste space in the vector for storing a vtable-pointer, and would instead construct fat pointers dynamically when needed (since it knows the type, it knows which vtable to inject in the fat pointer).

> you would store the concrete structs continously in Rust as well. Rust would also not waste space in the vector for storing a vtable-pointer, and would instead construct fat pointers dynamically when needed (since it knows the type, it knows which vtable to inject in the fat pointer). Uh, what? How is the compiler just supposed to magically know which of the structures in the array are of what type, without any add…

I meant to say homogenous array, which I assume you were talking about.

Re: Abstraction without overhead: traits in Rust

#116
post #93

Earlier quoted context omitted.

What is the representation for a type like Box ? Is there an extra indirection to get each of the vtables? Is there synthesized combined trait type and just one vtable pointer?

I am pretty sure you can't actually construct such a type (at least not at the moment) so Rust sort of sidesteps the question.

IIRC you can.

Re: Abstraction without overhead: traits in Rust

#117
post #9
post #5

Great article. The main bit of new information for me was that while Rust supports dynamic dispatch, its implementation has a noticeable difference from C++. In C++, the vtable pointer is in the object itself. In Rust, it's stored inside what is essentially a "fat pointer." Pointers to traits ("trait objects") are actually two pointers: the pointer to the vtable and the pointer to the actual object. This seems to hav…

This is also how Go does it. It looks like Rust traits can do everything Go interfaces can do, and more?

Go's interfaces have these additional features:

- They auto-implement on types that have the appropriate methods (a feature that probably is unwanted in Rust) - They can be runtime downcasted via `.(type_name_here)` - They can be runtime type switched via `switch foo.(type)`

I'm not sure of the vtable internals though.

Re: Abstraction without overhead: traits in Rust

#118
post #2

There is always overhead when adding abstractions--the only question is whether you pay at runtime or at compile time. C++ (and presumably Rust) choose the latter, Python and Go choose the former.

Technically Rust (and C++, IIRC) choose both, but the mindsets of most Rust(/C++) programmers/libraries is to use lower cost abstractions wherever possible. Rust provides features and libraries that provide a dynamic alternative to many different statically checked things; eg trait objects, cell types (internal mutability), shared pointers, etc.

The difference is in the mindset: Most Rust programmers will hem and haw at having to use Box until we don't have any other viable alternative (with Rust and its enums, there usually are many better ways to do it with lower cost). Java/Go libraries are completely okay with using dynamic dispatch everywhere. While writing Java code I won't be concerned about using an interface type or `Object` or whatever because zero-cost abstractions are not Java's thing. Of course, if there is a static alternative I will still prefer it, but I won't be too bothered if I just stick with `Object`.

Re: Abstraction without overhead: traits in Rust

#119
post #28

> Traits are interfaces So why not use "interface" keyword?

Probably for the same reason that they call their unions "enums" or their heap blocks "boxes". Standardization of jargon has never been a thing with rust, just roll with it.

And I guess by "standardization" you mean use a C-like name, even though it is inaccurate and misleading and the data type declaration is taken from another language family (ML)?

(I agree that "enum" is a wrong name to use, but apparently for different reasons.)

Re: Abstraction without overhead: traits in Rust

#120

Earlier quoted context omitted.

Because trait is a much better word for it: https://en.wikipedia.org/wiki/Trait_(computer_programming)

So in Rust traits can include full methods bodies, not only signatures?

They can also contain associated constants.
Post reply on HN