|
|
Log in / Subscribe / Register

The same old arguments...

The same old arguments...

Posted Dec 7, 2025 9:39 UTC (Sun) by Sesse (subscriber, #53779)
In reply to: The same old arguments... by josh
Parent article: Eventual Rust in CPython

> C++ generics don't support dynamic linking either

This is only true for a pretty narrow definition of “support”. It is true that _someone_ has to monomorphize the generic before it can be linked (since the only real experience AFAIK is either a VM or type erasure?); but that's true whether we're talking static or dynamic linking. Lots of C++ dynamic libraries expose functions involving these specializations; e.g., std::string is a generic (std::basic_string<char>) and libstdc++.so exposes a lot of functions related to it. In practice, you can upgrade libstdc++ pretty freely without anything related to vector, string, map, etc. breaking—but you can't easily change their internals, since they become effectively part of the ABI (like so many other things in C).


to post comments

The same old arguments...

Posted Dec 7, 2025 18:43 UTC (Sun) by JoeBuck (guest, #2330) [Link] (4 responses)

Right; I expect that at some point the most commonly used generics in the standard library will have their implementations frozen enough so that a stable ABI can be produced and dynamic linking can be supported in Rust in more cases. This was done for C++ long ago.

The same old arguments...

Posted Dec 7, 2025 18:58 UTC (Sun) by josh (subscriber, #17465) [Link] (3 responses)

I doubt we'll ever stabilize the internal layout of anything more complicated than `Result` or `Option` (and even for those, doing so means giving up on any further opportunities for niche optimization, the mechanism by which types like `Option<&T>` is the same size as `&T`).

For something like `Vec` or `HashMap`, the most likely path to stabilization is an opaque pointer plus a vtable of methods.

The same old arguments...

Posted Dec 7, 2025 23:40 UTC (Sun) by JoeBuck (guest, #2330) [Link] (2 responses)

That would be crazily inefficient for Vec<i32> or other vector of atomic type. If the call is not inlined, the structure could be frozen, as it is for std::vector<int> in C++ when libstdc++ is in use. Likewise for string slice arguments.

The same old arguments...

Posted Dec 7, 2025 23:43 UTC (Sun) by josh (subscriber, #17465) [Link] (1 responses)

We could nail down slices easily enough. It might potentially be reasonable to give *some* direct access to `Vec`, since the triple of pointer, length, and capacity is the obvious implementation; that would allow efficient and vectorized access to the data. However, for instance, reallocation would likely still require a vtable call.

The same old arguments...

Posted Dec 9, 2025 19:41 UTC (Tue) by NYKevin (subscriber, #129325) [Link]

After careful consideration, I don't think Vec needs vtables for reallocation, because those vtables really should attach to Allocator instead of Vec. But we do need some ABI glue that currently does not exist:

* In the case of Vec<T> a/k/a Vec<T, Global>, Global is a well-known ZST that can be statically dispatched. No need for a vtable. This is the most common case, so ideally it should not be pessimized in order to support other cases (especially seeing as the global allocator can be replaced). The foreign code will need to call into Rust's global allocation routines, but you have to do that even in the (default) case where Global delegates to System, so that's unavoidable.
* In the case of Vec<T, A> where A is a ZST or never dropped, the ABI needs glue code to coerce the whole thing into Vec<T, &'static dyn Allocator>, and then the vtable logic lives in Allocator where it belongs. I'm assuming, of course, that we can also nail down the ABI of &dyn Trait, which is a whole other kettle of fish. But at least dyn Trait is explicitly designed to support dynamic dispatch - most of the technical choices have already been made.
* In the case of Vec<T, &'a A>, it's the same story but with a lifetime parameter. Not sure how well that translates over the ABI, but at least lifetimes add no extra gunk at runtime.
* In the general case, the Vec might own an allocator, which might not be a ZST. That coercion is more complicated because now the Vec itself is of unknown size (it directly contains the allocator's fields). I would be inclined to declare that as unsupported or at least out of scope for language-level support, in the interests of not overly pessimizing Vec<T, Global> to support a niche corner case. Probably it could still be supported at the library level by decoupling the ownership of the Allocator from the Vec, and instead passing Vec<T, &'a dyn Allocator>. But that conversion is complicated and unsafe, so maybe some kind of glue code would be helpful here as well. Or maybe this version of Vec really does need a vtable.


Copyright © 2026, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds