Is there a way in rust to enforce the is_not_a_ref ? The reason here is that I am okay with
pub struct Dog {}
data: Vec<& Dog> // okay with this
data: Vec<&& Dog> // want to avoid this
data: Vec<&&& Dog> // also want to avoid this
The problem here is that with type inference, if it infers a & Dog instead of a Dog, it might end up creating a data: Vec<&& Dog> which I am trying to avoid.
T: 'static rules out any reference other than &'static Dog, which is pretty rare. The downside is that type inference can still infer a reference and you'll get a rather cryptic error in that case.
You can have a 'static bound, which will prevent temporary references, but not &'static. I'm not sure this is what you want though. (I don't understand what you're aiming for, really.)
I have some vague notion there may be a relation with blanket deref bounds, but it smells a bit like negative bounds.
I agree that my original question was not very clear. Let me try to motivate this. Suppose we have a struct Array (which is basically a Vec), and the following:
Things like Array<&&T> are silly because when we try to deref, we have to read multiple places in memory to get to the T -- and I would like a way to "ban" the construction of things like Array<&&T>.
I'm okay with Array<T> -- just things laid out in memory.
I'm also okay with Array<&T> (suppose we do a filter, but T is big and we don't want to copy). Array<&&T> is silly and I would like to ban this.
Yeah, I think I get it now. It's an interesting restriction. 'static may be good enough, in a practical sense. Anything more precise I've considered so far doesn't really work because a generic T could be a reference (or smart pointer).
This is usually not a good idea, because you don't know up front what someone is using this for or how desperately they need to do what you're trying to ban. And even if you did ban references, you've still got raw pointers, Box, and Arc et al causing the exact same problems. If you somehow forbid all of those, then users will stick usize in there and go look things up in an array elsewhere, which is also an inefficient double indirection.
This is an internal API where I am designer & user.
I don't forbid references. Vec<&T> is fine. I just don't want a chain of functions auto generating a Vec<&&&&&&&&&T>.
I'm also not trying to prevent multiple levels of indirection from the program. I just want to prevent them from accidentally happening_ due to chaining a bunch of iter / map / filter / scan's.
I don't know about you, but chain a few iter functions together, and I often unintentionally get &&T at places I'm expecting a &T. This is the problem I am trying to solve.
Can't say that's a problem I've ever had. If you take ownership of your input argument you can't return a reference to it, so that should be the way you handle that. I'd like to see an example of your wrapping functions, because they're maybe doing something wrong.
You cannot, in the first place, define functions with the signatures of group_by_1 and filter_1 because they appear to return references to their input arguments.
Note that in Iterator::filter, which is the most common way of obtaining a &&T by "accident", the && only appears inside the closure, and it cannot escape, so you can't continue to accidentally nest references (to &&&, etc.) by adding filters to the same iterator chain. You can get additional levels of references by nesting more things inside the filter closure, but that is more visually complex and impossible to overlook because the inner stuff will be indented more.
The compiler distinguishes between references and non-references in it's * (dereference) implementation. But I couldn't figure out a way to exploit this. Interesting side-note: You can dereference a &T in const context, but not utilize Deref::deref, which at least exposes the difference.
In classic fashion, after thinking about this for a minute after posting I realized that it probably can be exploited with a macro. I have to leave for now; perhaps someone else will get to it before I try.
Macro expansion happens before type checking right? So it seems, if we were to do this at compile time, this would be some type of "useless (at runtime)" const expr where depending on the value of std::any::type_name::(); , we either get a type error (say dimension mismatch) or everything goes smoothly?
I was thinking of something that didn't depend on type_name, something like a const function or other context that fails when given a type that's not shallow enough. You can't have a generic const function on stable, and if you have a generic function the references get hidden behind the type parameter anyway. But you can sometimes side-step those limitations with macros.
Probably still pretty limited, if possible, because the case that breaks under const is when Deref must be used (or implemented) because you don't have a reference; it's limited in the wrong direction. So it might have to be in a must-fail test block or something. And supposedly some day the const limitation will go away.