Generic bound ensuring non-reference argument - rust

The real reason to do this is beyond the scope, I just can say that it's related to a very unusual memory layout on some embedded platform. The goal is to make a wrapper for statics which can do some manual address translation on dereferencing. So putting a reference inside is pointless and unsafe. Alternatively I can make two implementations for references and not references but they must be strongly unambiguous.

You can do this but it requires the nightly features negative_impls and auto_traits:
#![feature(negative_impls)]
#![feature(auto_traits)]
auto trait NotRawRef {}
impl<T> !NotRawRef for &T {}
impl<T> !NotRawRef for &mut T {}
fn foo<T: NotRawRef>(_: T) {}
This will apply recursively by default, so T cannot be a user-defined type that contains a reference -- unless the user-defined type explicitly implements NotRawRef. You have to trust callers of your function not to implement this trait when it's not appropriate.
If nightly isn't an option, or if this is too strict, you can rather easily bound on "if there are any references, they must have static lifetime" with 'static. For example:
fn foo<T: 'static>(_: T) { }
fn main() {
let x = 1;
foo(x);
// The following line would fail with E0597:
// foo(&x);
// Works because the reference has static lifetime
foo(&1);
}
This bound applies to user-defined types that have generic lifetime parameters as well, and will reject any such type with a non-'static lifetime argument.

Related

Is it possible to return a `Keys<'_, K, V>` iterator as an more generic iterator of `&K`?

I would to write a method that returns self.hash_map.keys() while hiding from the caller the concrete type Keys<'_, K, V>.
A downside of the Keys return type is that it exposes to the caller that the K elements are coming from a HashMap. Intuitively, it seems as though it shouldn't be necessary to expose this information.
What is the cheapest way (with respect to CPU/allocations) to return an iterator of key references?
Can it be accomplished by some precise choice of return type? Is some form of type-erasure possible?
Or does it require an invocation in the function body? Is some transformation necessary?
Both of the options you speculated about are possible.
The simplest option is to use the impl type syntax, which is an “existential” type: “I am going to return a value which implements Iterator but I'm not telling you what the concrete type is”. In this case, the compiler knows what the type is (so the compiled code is exactly the same as if it wasn't hidden), but the user of your method cannot rely on anything but the specified trait, so you aren't leaking implementation details.
impl MyType {
fn keys(&self) -> impl Iterator<Item = &MyKeyType> {
self.hash_map.keys()
}
}
(Note that this resembles but is not the same as dyn Iterator; when you use dyn, you're using runtime dispatch and the same function can return different concrete types from different calls to it. With impl, the type is static, just hidden, and there is no overhead.)
The disadvantage of this option is that the type is entirely unnameable; for example, nobody can write a structure that holds your keys() iterator except by making it generic over all Iterators. (This is rarely a problem for iterators in particular, since iterator wrappers are usually generic anyway.)
Also, if your iterator implements any additional traits you want to allow the caller to use, like Debug or ExactSizeIterator, then you need to add them to the impl type or they won't be visible.
Another option is to wrap the iterator in your own struct. This allows you to hide the implementation type while still allowing callers to refer to it by name, so it's the most flexible. The disadvantage of this option is that you have to explicitly implement Iterator (and any other traits) for the wrapper:
impl MyType {
fn keys(&self) -> MyKeyIterator<'_> {
MyKeyIterator(self.hash_map.keys())
}
}
#[derive(Clone, Debug)]
struct MyKeyIterator<'a>(Keys<'a, MyKeyType, MyValueType>);
impl<'a> Iterator for MyKeyIterator<'a> {
type Item = &'a MyKeyType;
fn next(&mut self) -> Option<&'a MyKeyType> {
self.0.next()
}
}
Rust Playground link with supporting code
This wrapper should not add any performance cost (when compiled with optimization), except that by default the wrapper method will not be inlined if called from another crate. If you're writing a library and this method is performance-sensitive, you can either enable link-time optimization (LTO) in the build, or add #[inline] to the next method (which enables cross-crate inlining). Of course, don't do any such tweaking without checking whether it makes a difference to actual performance; otherwise you're just increasing compile time (and instruction cache thrashing).
Can it be accomplished by some precise choice of return type? Is some form of type-erasure possible?
Yes! You can return an impl Trait to indicate that you're returning a type that implements Trait but doesn't expose the concrete type:
fn keys(&self) -> impl Iterator<Item = &K> {
self.hash_map.keys()
}
See it working on the playground.

Implementing a trait that has associated trait types

I'm having trouble learning about associated types. My problem code:
trait Fooer {
fn foo(&self);
}
trait FooStore {
type T: Fooer;
fn store_foo(&self, fooer: Self::T);
}
#[allow(dead_code)]
struct DB {}
impl FooStore for DB {
type T = Fooer;
fn store_foo(&self, _fooer: Self::T) {}
}
fn main() {}
Play link
The intent here is to use associated types to make the FooStore trait not require the awkward and problematic syntax of impl<F:Fooer, T: FooStore<F>> FooStore<F> for DB because that often complains about F not being used.
However, the official docs on this feature show objects implementing the underlying associated type - but not traits. In this example, DB does not know what structs might be passed into store_foo(..), so it needs to use a trait to solve this issue.
With that said, how can I get an associated type to use a trait during impl? That is, how can I write type T = Fooer;? Or am I using this wrong somehow?
Note: I'm having some trouble constructing this example, I'm trying to correct this now. The error I was having is:
cargo: the trait `Fooer` cannot be made into an object [E0038]
The intent here is to use associated types to make the FooStore trait not require the awkward and problematic syntax of impl<F:Fooer, T: FooStore<F>> FooStore<F> for DB because that often complains about F not being used.
Your struct DB needs to assign a concrete type that implements Fooer to FooStore::T. Fooer is a trait, but can also be used as an unsized type. However, you can't use an unsized type here, because you can't pass an argument of an unsized type by value (which FooStore::store_foo requires).
If you don't want DB to assign a particular type to FooStore::T, then you can make DB generic.
use std::marker::PhantomData;
#[allow(dead_code)]
struct DB<F: Fooer> {
_phantom: PhantomData<F>,
}
impl<F: Fooer> FooStore for DB<F> {
type T = F;
fn store_foo(&self, _fooer: Self::T) {}
}
Notice the use of PhantomData: we use it to force the parameter T to be used, and it also indicates that DB<T> conceptually owns objects of type T.

Trait with methods that take generic parameters [duplicate]

When compiling the following code:
trait RenderTarget {}
struct RenderWindow;
impl RenderTarget for RenderWindow {}
trait Drawable {
fn draw<RT: RenderTarget>(&self, target: &mut RT);
}
fn main() {
let mut win = RenderWindow;
let mut vec: Vec<Box<Drawable>> = Vec::new();
for e in &vec {
e.draw(&mut win);
}
}
I get the error:
error: the trait `Drawable` is not implemented for the type `Drawable` [E0277]
src/main.rs:15 e.draw(&mut win);
^~~~~~~~~~~~~~
What is the error message trying to tell? Also, how to fix it?
There's a related question but the solution there was to modify the trait A (which corresponds to Drawable in my case), but that's not possible here since Drawable is from an external library.
Update: fixed object safety rules to the 1.0 version of them. Namely, by-value self makes method object-unsafe no longer.
This error happens because of object safety.
In order to be able to create a trait object out of a trait, the trait must be object-safe. A trait is object-safe if both of these statements hold:
it does not have Sized requirement, as in trait Whatever: Sized {};
all its methods are object-safe.
A method is object-safe if both of these statements are true:
it has where Self: Sized requirement, as in fn method() where Self: Sized;
none of the following statements holds:
this method mentions Self in their signature in any form, even under a reference, except associated types;
this method is static;
this method is generic.
These restrictions are in fact fairly natural if you think more of them.
Remember that when values are made into trait objects, actual information of their type is erased, including their size. Therefore, trait objects can only be used through a reference. References (or other smart pointers, like Box or Rc), when applied to trait objects, become "fat pointers" - along with the pointer to the value, they also contain a pointer to the virtual table for that value.
Because trait objects can only be used through a pointer, by-value self methods can't be called on them - you'd need the actual value in order to call such methods. This was a violation of object safety at one point, which meant that traits with such methods couldn't be made trait objects, however, even before 1.0 the rules had been tweaked to allow by-value self methods on trait objects. These methods still can't be called, though, due to the reason described above. There are reasons to expect that in the future this restriction will be lifted because it currently leads to some quirks in the language, for example, the inability to call Box<FnOnce()> closures.
Self can't be used in methods which should be called on trait objects precisely because trait objects have their actual type erased, but in order to call such methods the compiler would need to know this erased type.
Why static methods can't be called on trait objects, I guess, is obvious - static methods by definition "belong" to the trait itself, not to the value, so you need to know the concrete type implementing the trait to call them. More concretely, regular methods are dispatched through a virtual table stored inside a trait object, but static methods do not have a receiver, so they have nothing to dispatch on, and for this reason they can't be stored in a virtual table. Thus they are uncallable without knowing the concrete type.
Generic trait methods can't be called for another reason, more technical than logical, I think. In Rust generic functions and methods are implemented through monomorphization - that is, for each instantiation of a generic function with a concrete set of type parameters the compiler generate a separate function. For the language user it looks like that they're calling a generic function; but on the lowest level for each set of type parameters there is a separate copy of the function, specialized to work for the instantiated types.
Given this approach, in order to call generic methods on a trait object you would need its virtual table to contain pointers to virtually each and every possible instantiation of the generic method for all possible types, which is, naturally, impossible because it would require infinite number of instantiations. And so calling generic methods on trait objects is disallowed.
If Drawable is an external trait, then you're stuck - it is impossible to do what you want, that is, to call draw() on each item in a heterogeneous collection. If your set of drawables is statically known, you can create a separate collection for each drawable type or, alternatively, create your own enum which would contain a variant for each drawable type you have. Then you can implement Drawable for the enum itself, which would be fairly straightforward.
I refer to Vladimir's excellent answer which explains Object's safety, however I am afraid than in the middle of the discussion the concrete problem at hand was forgotten.
As Vladimir mentions, the issue is that a method generic over types (generic over lifetimes is fine) renders the trait it belongs to unusable for run-time polymorphism; this, in Rust, is called Object Safety.
The simplest fix, therefore, is to remove the generic parameter of the method!
trait RenderTarget {}
struct RenderWindow;
impl RenderTarget for RenderWindow {}
trait Drawable {
fn draw(&self, target: &mut RenderTarget);
}
fn main() {
let mut win = RenderWindow;
let mut vec: Vec<Box<Drawable>> = Vec::new();
for e in &vec {
e.draw(&mut win);
}
}
The main difference between:
fn draw<RT: RenderTarget>(&self, target: &mut RT)
and
fn draw(&self, target: &mut RenderTarget)
is that the latter requires RenderTarget to be Object Safe too as it is now used in a run-time polymorphism situation (so, no static method, no generic method, no Self, ...).
Another (more technical) difference is that the former is "monorphised" at compile-time (that is RT is substituted with the real type and all relevant optimizations applied) whereas the latter is not (and so, no such optimizations occur).
If you're stuck with what you're given, there are two options you could try.
In this case, you can't, but if you were given an unsized RenderTarget
trait Drawable {
fn draw<RT: RenderTarget + ?Sized>(&self, target: &mut RT);
}
you could implement
trait DrawableDynamic {
fn draw(&self, target: &mut RenderTarget);
}
impl<T: Drawable> DrawableDynamic for T {
fn draw(&self, target: &mut RenderTarget) {
Drawable::draw(self, target)
}
}
to redirect the types you're given to an object-safe dynamically dispatched alternative. It looks like such a change could be made upstream, since you can't really use the fact that RT is sized.
The other doesn't allow you to put arbitrary Drawables in your Vec, but should work without allowing unsized types upstream. This is to use an enum to wrap the possible values of the vector:
enum AllDrawable {
Square(Square),
Triangle(Triangle)
}
impl Drawable for AllDrawable {
fn draw<RT: RenderTarget>(&self, target: &mut RT) {
match *self {
AllDrawable::Square(ref x) => x.draw(target),
AllDrawable::Triangle(ref x) => x.draw(target),
}
}
}
One might want to add From implementations and such; you might find it easier if using wrapped_enum! which will automatically implement those for you.

How do I store a list of callbacks on a struct?

This is a follow-up to my question on how to create & use a list of callbacks.
I'm trying to create (and store, near an event loop) a list of callback functions that will be called at some indeterminate point in the future.
struct ComplexThing {
calls: Vec<Box<FnMut()>>,
}
impl ComplexThing {
fn call<'a, T: FnMut() + 'a>(&'a mut self, func: T) {
self.calls.push(Box::new(func));
}
}
Errors with:
calls.rs:30:25: 30:39 error: the parameter type `T` may not live long enough [E0310]
calls.rs:30 self.calls.push(Box::new(func));
^~~~~~~~~~~~~~
calls.rs:30:39: 30:39 help: consider adding an explicit lifetime bound `T: 'static`...
calls.rs:30:25: 30:39 note: ...so that the type `T` will meet its required lifetime bounds
calls.rs:30 self.calls.push(Box::new(func));
^~~~~~~~~~~~~~
I tried adding it to the struct, which fixed the error about lifetimes on the call to push,
struct ComplexThing<'a> {
calls: Vec<Box<FnMut() + 'a>>,
}
impl ComplexThing {
fn call<'a, T: FnMut() + 'a>(&'a mut self, func: T) {
self.calls.push(Box::new(func));
}
}
… but gets me:
calls.rs:28:6: 28:18 error: wrong number of lifetime parameters: expected 1, found 0 [E0107]
calls.rs:28 impl ComplexThing {
^~~~~~~~~~~~
Which, yes, I suppose the struct has a <'a>, and I'm not specifying it. If I add it,
impl ComplexThing<'a> {
I get,
calls.rs:28:19: 28:21 error: use of undeclared lifetime name `'a` [E0261]
calls.rs:28 impl ComplexThing<'a> {
I don't know if I should be specifying it on the struct ComplexThing or not. If I leave it off (and I would greatly prefer to, I think),
I think there's something crucial about how Rust notates lifetimes that I'm not getting here. The FnMut that ComplexThing is (presently) trying to store in a Box is (in the design in my head) owned by the instance of ComplexThing; it's lifetime should be less than that of .ComplexThing — i.e., one of two things would happen:
What will be a private function of the ComplexThing will end up removing the Box<FnMut> from the Vec (and thus, take ownership of it), run the FnMut, and then exit, thus freeing the FnMut.
The ComplexThing is deallocated, in which case the Vec and any Box<FnMut>'s are deallocated with it.
The question "How do I store a closure in Rust?"'s answer made me think a Box<FnMut> wouldn't need lifetime annotations, but the answer I got on how to create & use a list of callbacks makes me think I do.
My best guess is that Box is just storing a pointer to an object that I don't really own, and that I need to either create a copy of the FnMut on the heap, or move-construct one there, and then that copy is the one I can own. (Otherwise, if it's like a closure that's on the stack, I need to make sure that closure doesn't go out of scope before my Box does, which is why Rust is having me annotate lifetimes.)
'a on ComplexThing is a generic lifetime parameter and needs to be defined just as much as a generic type parameter. If you had a struct Foo<T>, you would not be able to write impl Foo<T> because there is no concrete type T in scope; if you want it to be generic, you need to define it, impl<T> Foo<T>. This allows you to write constraints too, such as impl<T: Clone> Foo<T> to implement methods on Foo<T> only where T is a type that implements Clone.
So then, the answer is simply that you need to define the lifetime 'a as generic:
impl<'a> ComplexThing<'a> { … }

What makes something a "trait object"?

Recent Rust changes have made "trait objects" more prominent to me, but I only have a nebulous grasp of what actually makes something into a trait object. One change in particular is the upcoming change to allow trait objects to forward trait implementations to the inner type.
Given a trait Foo, I'm pretty sure that Box<Foo> / Box<dyn Foo> is a trait object. Is &Foo / &dyn Foo also a trait object? What about other smart-pointer things like Rc or Arc? How could I make my own type that would count as a trait object?
The reference only mentions trait objects once, but nothing like a definition.
You have trait objects when you have a pointer to a trait.
Box, Arc, Rc and the reference & are all, at their core, pointers. In terms of defining a "trait object" they work in the same way.
"Trait objects" are Rust's take on dynamic dispatch.
Here's an example that I hope helps show what trait objects are:
// define an example struct, make it printable
#[derive(Debug)]
struct Foo;
// an example trait
trait Bar {
fn baz(&self);
}
// implement the trait for Foo
impl Bar for Foo {
fn baz(&self) {
println!("{:?}", self)
}
}
// This is a generic function that takes any T that implements trait Bar.
// It must resolve to a specific concrete T at compile time.
// The compiler creates a different version of this function
// for each concrete type used to call it so &T here is NOT
// a trait object (as T will represent a known, sized type
// after compilation)
fn static_dispatch<T>(t: &T)
where
T: Bar,
{
t.baz(); // we can do this because t implements Bar
}
// This function takes a pointer to a something that implements trait Bar
// (it'll know what it is only at runtime). &dyn Bar is a trait object.
// There's only one version of this function at runtime, so this
// reduces the size of the compiled program if the function
// is called with several different types vs using static_dispatch.
// However performance is slightly lower, as the &dyn Bar that
// dynamic_dispatch receives is a pointer to the object +
// a vtable with all the Bar methods that the object implements.
// Calling baz() on t means having to look it up in this vtable.
fn dynamic_dispatch(t: &dyn Bar) {
// ----------------^
// this is the trait object! It would also work with Box<dyn Bar> or
// Rc<dyn Bar> or Arc<dyn Bar>
//
t.baz(); // we can do this because t implements Bar
}
fn main() {
let foo = Foo;
static_dispatch(&foo);
dynamic_dispatch(&foo);
}
For further reference, there is a good Trait Objects chapter of the Rust book
Short Answer: You can only make object-safe traits into trait objects.
Object-Safe Traits: Traits that do not resolve to concrete type of implementation. In practice two rules govern if a trait is object-safe.
The return type isn’t Self.
There are no generic type parameters.
Any trait satisfying these two rules can be used as trait objects.
Example of trait that is object-safe can be used as trait object:
trait Draw {
fn draw(&self);
}
Example of trait that cannot be used as trait object:
trait Draw {
fn draw(&self) -> Self;
}
For detailed explanation: https://doc.rust-lang.org/book/second-edition/ch17-02-trait-objects.html
Trait objects are the Rust implementation of dynamic dispatch. Dynamic dispatch allows one particular implementation of a polymorphic operation (trait methods) to be chosen at run time. Dynamic dispatch allows a very flexible architecture because we can swap function implementations out at runtime. However, there is a small runtime cost associated with dynamic dispatch.
The variables/parameters which hold the trait objects are fat pointers which consists of the following components:
pointer to the object in memory
pointer to that object’s vtable, a vtable is a table with pointers which point to the actual method(s) implementation(s).
Example
struct Point {
x: i64,
y: i64,
z: i64,
}
trait Print {
fn print(&self);
}
// dyn Print is actually a type and we can implement methods on it
impl dyn Print + 'static {
fn print_traitobject(&self) {
println!("from trait object");
}
}
impl Print for Point {
fn print(&self) {
println!("x: {}, y: {}, z: {}", self.x, self.y, self.z);
}
}
// static dispatch (compile time): compiler must know specific versions
// at compile time generates a version for each type
// compiler will use monomorphization to create different versions of the function
// for each type. However, because they can be inlined, it generally has a faster runtime
// compared to dynamic dispatch
fn static_dispatch<T: Print>(point: &T) {
point.print();
}
// dynamic dispatch (run time): compiler doesn't need to know specific versions
// at compile time because it will use a pointer to the data and the vtable.
// The vtable contains pointers to all the different different function implementations.
// Because it has to do lookups at runtime it is generally slower compared to static dispatch
// point_trait_obj is a trait object
fn dynamic_dispatch(point_trait_obj: &(dyn Print + 'static)) {
point_trait_obj.print();
point_trait_obj.print_traitobject();
}
fn main() {
let point = Point { x: 1, y: 2, z: 3 };
// On the next line the compiler knows that the generic type T is Point
static_dispatch(&point);
// This function takes any obj which implements Print trait
// We could, at runtime, change the specfic type as long as it implements the Print trait
dynamic_dispatch(&point);
}
This question already has good answers about what a trait object is. Let me give here an example of when we might want to use trait objects and why. I'll base my example on the one given in the Rust Book.
Let's say we need a GUI library to create a GUI form. That GUI form will consist of visual components, such as buttons, labels, check-boxes, etc. Let's ask ourselves, who should know how to draw a given component? The library or the component itself? If the library came with a fixed set of all the components you might ever need, then it could internally use an enum where each enum variant represents a single component type and the library itself could take care of all the drawing (as it knows all about its components and how exactly they should be drawn). However, it would be much better if the library allowed you to also use third-party components or ones that you wrote by yourself.
In OOP languages like Java, C#, C++ and others, this is typically done by having a component hierarchy where all components inherit a base class (let's call it Component). That Component class would have a draw() method (which could even be defined as abstract, so as to force all sub-classes to implement that method).
However, Rust doesn't have inheritance. Rust enums are very powerful, as each enum variant can have different types and amounts of associated data, and they are often used in situations where you'd use inheritance in a typical OOP language. An important advantage of using enums and generics in Rust is that everything is known at compile time, which means you don't need to sacrifice performance (no need for things like vtables). But in some cases, as in our example, enums don't provide enough flexibility. The library needs to keep track of components of different type and it needs a way to call methods on components that it doesn't even know about. That's generally known as dynamic dispatch and as explained by others, trait objects are the Rust way of doing dynamic dispatch.

Resources