In Rust, is there any way to change a struct/type to be "Send"? - rust

I've hit the issue a couple of times of trying to pass things into the spawn function (to create a new thread/task) and have the compiler tell me error: cannot capture variable of type "blah blah", which does not fulfill "Send", in a bounded closure.
Is there a way to transform a type be able to fulfill "Send" or is that fixed based on some set of rules?
For example, I can easily implement the ToStr trait by using a directive like this:
#[deriving(ToStr, Rand)]
struct Point {
x: int,
y: int,
}
Can I do something similar for the Send trait? Or are "kind" Traits treated differently?
Here's a concrete example of this issue - is there some way to overcome it?
fn create_process_options(cmdinfo: &CmdInfo) -> (ProcessOptions, Option<FileDesc>) {
// ... omitted
}
// "po" is of type std::run::ProcessOptions
let (po, filedesc_opt) = create_process_options(&cmdinfo);
spawn(proc() {
let mut ps = Process::new(cmdinfo.program, cmdinfo.args, po).expect("darn");
ps.finish();
});
Compiler error:
error: cannot capture variable of type `std::run::ProcessOptions<>`, which does not fulfill `Send`, in a bounded closure
let mut process = Process::new(cmdinfo.program, cmdinfo.args, po).expect("darn");
^~
note: this closure's environment must satisfy `Send`
let mut process = Process::new(cmdinfo.program, cmdinfo.args, po).expect("darn");

Send is a rust Kind, the other things you mentioned are Traits. While both can be used to bound generics, they are in fact quite different. You have to opt-in to a Trait, but what Kinds a type has are inferred based on their contents - besides changing the contents you can't change the Kind of a type.
For most Kinds, the rule is "a type X is of Kind Y if all the members of X are of Kind Y."
In this case, since being Send requires that you fulfill 'static, which means that they don't contain any non-'static references. Since ProcessOptions contains a non-static lifetime Option<&'a Path>, like Chris Morgan detailed in his comment, ProcessOptions does not fulfill Send.

Related

Variadic generic trait paramterised on same type in Rust

I would broadly like to write something like this:
pub struct Example<..T> {...}
That is, parametrise Example over any number of type T. This is discussed in an RFC, but this seems to be quite stale.
I know that we can have variadic functions by using c_variadic. Is there any way to expand this to structs?
Edit to include more concrete example:
What I am trying to do is (may not be valid Rust, but just an example):
// `a` and `b` are some structs that communicate via channels
// Label is some label we can match on
// Continuation is a trait
let options = vec![(label1, cont1), (label2, cont2)...];
let a = Offer<...(Label, Continuation)>::new();
let b = Pick<Label>::new();
// offer and pick are just some functions that communicate
// the choice via channels
// The important part being that offer and pick would be parametrised
// over <..(Label, Continuation)>
let picked = a.offer(options);
let picked = b.pick(label1);
Perhaps you want a const size parameter:
struct Offer<T, const U: usize> {
contents: [T; U]
}
This can represent a list of any size. All items must be of the same type though but in your example this seems to be the case.

Pass struct generic type to trait generic method [duplicate]

In this question, an issue arose that could be solved by changing an attempt at using a generic type parameter into an associated type. That prompted the question "Why is an associated type more appropriate here?", which made me want to know more.
The RFC that introduced associated types says:
This RFC clarifies trait matching by:
Treating all trait type parameters as input types, and
Providing associated types, which are output types.
The RFC uses a graph structure as a motivating example, and this is also used in the documentation, but I'll admit to not fully appreciating the benefits of the associated type version over the type-parameterized version. The primary thing is that the distance method doesn't need to care about the Edge type. This is nice but seems a bit shallow of a reason for having associated types at all.
I've found associated types to be pretty intuitive to use in practice, but I find myself struggling when deciding where and when I should use them in my own API.
When writing code, when should I choose an associated type over a generic type parameter, and when should I do the opposite?
This is now touched on in the second edition of The Rust Programming Language. However, let's dive in a bit in addition.
Let us start with a simpler example.
When is it appropriate to use a trait method?
There are multiple ways to provide late binding:
trait MyTrait {
fn hello_word(&self) -> String;
}
Or:
struct MyTrait<T> {
t: T,
hello_world: fn(&T) -> String,
}
impl<T> MyTrait<T> {
fn new(t: T, hello_world: fn(&T) -> String) -> MyTrait<T>;
fn hello_world(&self) -> String {
(self.hello_world)(self.t)
}
}
Disregarding any implementation/performance strategy, both excerpts above allow the user to specify in a dynamic manner how hello_world should behave.
The one difference (semantically) is that the trait implementation guarantees that for a given type T implementing the trait, hello_world will always have the same behavior whereas the struct implementation allows having a different behavior on a per instance basis.
Whether using a method is appropriate or not depends on the usecase!
When is it appropriate to use an associated type?
Similarly to the trait methods above, an associated type is a form of late binding (though it occurs at compilation), allowing the user of the trait to specify for a given instance which type to substitute. It is not the only way (thus the question):
trait MyTrait {
type Return;
fn hello_world(&self) -> Self::Return;
}
Or:
trait MyTrait<Return> {
fn hello_world(&Self) -> Return;
}
Are equivalent to the late binding of methods above:
the first one enforces that for a given Self there is a single Return associated
the second one, instead, allows implementing MyTrait for Self for multiple Return
Which form is more appropriate depends on whether it makes sense to enforce unicity or not. For example:
Deref uses an associated type because without unicity the compiler would go mad during inference
Add uses an associated type because its author thought that given the two arguments there would be a logical return type
As you can see, while Deref is an obvious usecase (technical constraint), the case of Add is less clear cut: maybe it would make sense for i32 + i32 to yield either i32 or Complex<i32> depending on the context? Nonetheless, the author exercised their judgment and decided that overloading the return type for additions was unnecessary.
My personal stance is that there is no right answer. Still, beyond the unicity argument, I would mention that associated types make using the trait easier as they decrease the number of parameters that have to be specified, so in case the benefits of the flexibility of using a regular trait parameter are not obvious, I suggest starting with an associated type.
Associated types are a grouping mechanism, so they should be used when it makes sense to group types together.
The Graph trait introduced in the documentation is an example of this. You want a Graph to be generic, but once you have a specific kind of Graph, you don't want the Node or Edge types to vary anymore. A particular Graph isn't going to want to vary those types within a single implementation, and in fact, wants them to always be the same. They're grouped together, or one might even say associated.
Associated types can be used to tell the compiler "these two types between these two implementations are the same". Here's a double dispatch example that compiles, and is almost similar to how the standard library relates iterator to sum types:
trait MySum {
type Item;
fn sum<I>(iter: I)
where
I: MyIter<Item = Self::Item>;
}
trait MyIter {
type Item;
fn next(&self) {}
fn sum<S>(self)
where
S: MySum<Item = Self::Item>;
}
struct MyU32;
impl MySum for MyU32 {
type Item = MyU32;
fn sum<I>(iter: I)
where
I: MyIter<Item = Self::Item>,
{
iter.next()
}
}
struct MyVec;
impl MyIter for MyVec {
type Item = MyU32;
fn sum<S>(self)
where
S: MySum<Item = Self::Item>,
{
S::sum::<Self>(self)
}
}
fn main() {}
Also, https://blog.thomasheartman.com/posts/on-generics-and-associated-types has some good information on this as well:
In short, use generics when you want to type A to be able to implement a trait any number of times for different type parameters, such as in the case of the From trait.
Use associated types if it makes sense for a type to only implement the trait once, such as with Iterator and Deref.

How to store an invariant type variable in Rust

I would like to parse the type of each value in a row of data from tokio-postgresql
Here is an example of getting a single value for a row of data from postgresql:
...
let rows = client
.query("select * from ExampleTable;")
.await?;
// This is how you read a string if you know the first column is a string type.
let thisValue: &str = rows[0].get(0);
In this example, it is known at design-time that the type in the first column is a string, and therefore the type for thisValue is &str. I would like to accept an invariant type.
I intend to use std::any::type_name::<T>() to derive the type name in thisValue and then use conditional logic (if/switch) to process this data differently depending on the type.
Is there an invariant way to store a variable in Rust? Will std::any::type_name::<T>() work on that variable? Is there another way to "box" the variable instead?
I understand that std::any::type_name::<T>() is using a kind of generics interface. To me, this means it's probably a compile-time strategy, not run-time. So I have my doubts that the way I am researching will work, but I hope I am on the right track and only need the final piece: an invariant type.
Should I be using &dyn Any and TypeId::of::<TypeHere>() == thisValue.type_id()?
In this situation, the get function of this API tokio-postgresql uses generics and doesn't return a boxed value. Therefore in this situation I may need to use columns() to determine the Rust type and the use separate functions to call get with different variables types.
The overall question still needs to be answered "How to store an invariant type variable in Rust", regardless of the specifics I have used to ask the title question.
The preferred invariant type is &dyn any
With &dyn any: any is the trait, dyn means the type of the trait.
Declaring:
let thisValue: &dyn Any = rows[0].get(0); //This works if tokio-postgresql returned a "dyn any" type, which it doesn't
Example of testing what type is referenced:
TypeId::of::<String>() == thisValue.type_id() //type checking using TypeId of boxed value.
Example of testing the type with downcast:
if let Some(string) = thisValue.downcast_ref::<String>() {
println!("String ({}): {}", string.len(), string);
}
Boxed
Box to force heap allocation (if necessary). This strategy is included too, so you can see how &dyn Any works with Boxed
A "boxed" value of dyn Any is invariant:
let thisValue: Boxed<dyn Any> = rows[0].get(0); //This works if tokio-postgresql returned a "dyn any" type, which it doesn't
In this scenario the API being used requires generic inference, so for tokio-postgresql this won't work, but it is the answer for the title question.
An example of testing the type with the downcast function of Boxed:
if let Ok(string) = thisValue.downcast::<String>() {
println!("String ({}): {}", string.len(), string);
}
About the postgresql sub-problem
As per the original post,
In this situation, the get function of this API tokio-postgresql uses
generics and doesn't return a boxed value. Therefore in this situation
I may need to use columns() to determine the Rust type and the use
separate functions to call get with different variables types.
So this answer solves the question, and although it won't work with the tokio-postgresql API, it equips you with the knowledge of the kind of API you would like to find/build/wait-for.

Idiomatic way of binding function arguments and passing around bound functions

Is there an idiomatic Rust way of binding function arguments and producing a new function?
For example, suppose I had the following functions:
fn eq(a: i32) -> Box<Fn(i32) -> bool> {
let target = a; // copy
Box::new(move |value| value == target)
}
fn evaluate(func: Box<Fn(i32) -> bool>, value: i32) -> bool {
func(value)
}
Is the Box mechanism used by eq a sane way of binding an argument to a function for usage in evaluate? e.g. something like this:
let is_42 = eq(42);
assert_eq!(true, evaluate(is_42, 42));
There's also the issue of lifetimes. I'm wondering what the correct semantics would be for extending the lifetime of target in eq(), so its lifetime is bound to the lifetime of the boxed function.
Is there an idiomatic Rust way of binding function arguments and producing a new function?
Yes, Rust has closures which are literally functions + a bound environment.
Therefore, binding a function arguments, or partially applying it, is simply a matter of forming a closure which will invoke this function with a few fixed arguments.
Is the Box mechanism used by eq a sane way of binding an argument to a function for usage in evaluate?
It is, for now.
The problem of Rust closures is that they are Voldemort types (i.e., types that cannot be named). As a result, while you can assign a closure to a local variable, and let inference deduce the type, you cannot actually return it from a function1.
At the moment, the work around is thus to return -> Box<Fn(..) -> ..> in this situation.
However, your signature for evaluate is needlessly constraining. Instead of taking a Box, you could take a reference:
fn evaluate(f: &Fn(i32) -> bool, value: i32) -> bool { f(value) }
This will let a user who can call evaluate directly free NOT to allocate on the heap (which Box does).
1 There is ongoing work to allow specifying a return type as -> impl SomeTrait which would allow you to do so.
There's also the issue of lifetimes. I'm wondering what the correct semantics would be for extending the lifetime of target in eq(), so its lifetime is bound to the lifetime of the boxed function.
It is not possible to extend a lifetime; a lifetime is descriptive, not prescriptive: it is merely a notation to denote the actual lifetime, not a way to specify the lifetime a value should have.
For closures, you may want to move their environments inside the closure; taking to capture by value and not reference. It should solve most lifetime issues.
For the remaining lifetime issues, you actually go the other way around and constrain the type of the closure by denoting the lifetime of its environment: F: Fn(i32) -> bool + 'a marks that F is only valid for 'a.

How do I solve the "missing associated type `Err` value" error?

I'm trying to make a simple utility function that reads multiple elements from stdin and puts them in collection and returns it. However I'm stuck at this point. The compiler says missing associated type Err value. How do I make it work, while keeping it generic as possible?
While this function seems useless, it's for learning the language and its type system.
use std::io::{ stdin };
use std::str::FromStr;
use std::io::Read;
use std::iter::FromIterator;
pub fn read_all<C>() -> C
where C: FromIterator<FromStr<Err>>
{
let mut buff = String::new();
stdin().read_to_string(&mut buff).expect("read_to_string error");
buff.split_whitespace()
.filter_map(|w| w.parse().ok())
.collect()
}
Usage example:
let v: Vec<i32> = read_all();
Working code
The only thing you need to change to your code in order to make it compile is the type signature of the function:
pub fn read_all<C, F>() -> C
where F: FromStr,
C: FromIterator<F>
Explanation
Your code is almost correct, but there is a problem:
FromIterator<T> is a trait, but T is a type.
You use FromStr in the place of T, but FromStr is a trait, not a type.
To solve this, you need to get a type that implements FromStr. You can do this by adding a type parameter F to the function and constraining it with where F: FromStr. Then you can write FromIterator<F>.
A note on associated types
Besides the issue of using a trait instead of a type, typing FromStr<Err> is wrong syntax. While in this case it is not necessary to specify the type of Err in the FromStr trait, you could do it as shown below:
pub fn read_all<C, F, E>() -> C
where F: FromStr<Err=E>,
C: FromIterator<F>
As you can see, instead of writing FromStr<E> we need to write FromStr<Err=E>. That is, you need to explicitly type the name of the associated type you are referring to.
A note on types vs traits
Usually traits cannot be treated as types. However, there are exceptions to this rule, as illustrated by the example below:
use std::fmt::Display;
pub fn print_box(thing: Box<Display>) {
println!("{}", thing)
}
fn main() { print_box(Box::new(42)); }
Here, you would expect T in Box<T> to be a type, but the Display trait is supplied instead. However, the compiler does not reject the program. The type checker sees Display as an unsized type. That is, the type of an object with a size unknown at compile time (because it could be any type implementing Display). When T in Box<T> is a trait, the resulting type is usually referred to as a trait object. It is impossible to cover this topic in depth here, but the links I refer to are a good starting point in case you want to know more.

Resources