How do I tell the compiler not to evaluate an argument? - rust

I'd like to instruct the Rust compiler to not evaluate an argument under any circumstance. Here is an example:
#![allow(dead_code)]
trait CheckTrait {
fn check(b : bool);
}
struct CheckStructA {}
struct CheckStructB {}
impl CheckTrait for CheckStructA {
fn check(_b : bool) {
println!("CheckStructA");
}
}
impl CheckTrait for CheckStructB {
// compiler: do not evaluate the argument _b
fn check(_b : bool) {
}
}
fn show_stuff_a() -> bool {
println!("Show stuff A");
true
}
fn show_stuff_b() -> bool {
println!("Show stuff B");
true
}
fn test_a<T : CheckTrait>(_ : T) {
T::check(show_stuff_a());
}
fn test_b<T : CheckTrait>(_ : T) {
T::check(show_stuff_b());
}
fn main() {
test_a(CheckStructA{});
test_b(CheckStructB{});
}
Here CheckStructB is effectively a disabled version of CheckStructA. Where the comment is, I would like to be able to instruct the compiler not to evaluate whatever expression computes _b for CheckStructB::check, but still evaluate whatever expression would compute _b for CheckStructA::check. The consequence on this code is that it would still output "Show Stuff A" to the console, but not output "Show Stuff B" to the console.
In C# this can be done by replacing the comment with [System.Diagnostics.Conditional("DoNotEverTurnThisOn")] . I do not want to define the types inside a macro because that breaks intellisense.
How do I do it in Rust?

Only evaluating arguments as necessary is called Lazy Evaluation.
In languages like Haskell, for which Lazy Evaluation is the default, an argument or variable of type bool is not actually represented as a bool immediately, instead it is represented as a "thunk" which contains the function to call and its own arguments (potentially thunks).
In Rust, since Eager Evaluation is the default, you need to explicitly represent laziness in the type of the argument or valuable. This is generally done by asking not for T but for FnOnce() -> T instead.
Therefore, you would rewrite check as:
fn check<F: FnOnce() -> bool>(condition: F);
Then, it's up to the implementation to either evaluate F or not, and if not evaluated nothing is executed.
Note: if you do not want a generic check, you can take Box<FnOnce() -> bool> as an argument; it will however require a heap allocation... just like in Haskell.
Let's see some code! Playground link
trait CheckTrait {
fn check<F: FnOnce() -> bool>(b: F);
}
struct CheckStructA {}
struct CheckStructB {}
impl CheckTrait for CheckStructA {
fn check<F: FnOnce() -> bool>(b: F) {
b();
println!("CheckStructA");
}
}
impl CheckTrait for CheckStructB {
fn check<F: FnOnce() -> bool>(_b: F) {
println!("CheckStructB");
}
}
fn show_stuff_a() -> bool {
println!("Show stuff A");
true
}
fn show_stuff_b() -> bool {
println!("Show stuff B");
true
}
fn test_a<T : CheckTrait>(_ : T) {
T::check(|| show_stuff_a());
}
fn test_b<T : CheckTrait>(_ : T) {
T::check(|| show_stuff_b());
}
fn main() {
test_a(CheckStructA{});
test_b(CheckStructB{});
}

Related

Is there idiomatic opposite of Result<T, Infallible>?

When one wants to show that trait returning Result should never fail the Infallible is used as an error type like in example below:
trait Foo {
type T;
type E: std::error::Error;
fn bar() -> Result<Self::T, Self::E>;
}
impl Foo for () {
type T = ();
type E = std::convert::Infallible;
fn bar() -> Result<Self::T, Self::E> { Ok(()) }
}
But what should one do with implementation that will always return Err and never Ok? Is there idiomatic way to fill the blank below:
impl Foo for MyCustomError {
type T = //what to put here as "never returned type";
type E = MyCustomError;
fn bar() -> Result<Self::T, Self::E> { Err(MyCustomError) }
}
Once never stabilizes you can just use that.
#![feature(never)]
impl Foo for MyCustomError {
type T = !;
type E = MyCustomError;
fn bar() -> Result<Self::T, Self::E> { Err(MyCustomError) }
}
Until then we can construct our own empty enum:
enum Void {}
impl Foo for MyCustomError {
type T = Void;
type E = MyCustomError;
fn bar() -> Result<Self::T, Self::E> { Err(MyCustomError) }
}
which can't be constructed for obvious reasons, Rust also sees that and optimizes accordingly.
Or use void::Void or Infallible which except for the different traits each implements are essentially the same.

Propagating higher-kinded-lifetimes? implementation of `Predicate` not general enough

I'm trying to write a Rust library that lets users define and compose predicates for certain kinds of data. This is all easy when the predicates act on owned data, but it's turning out to be harder when they act on borrowed data. I think it's easier to understand my problem by reading an annotated code example (I'm sorry I couldn't make it shorter, but I think everything in it is required to understand my situation).
// First, some of the types that I'm interested in writing predicates for. MyValue and
// MyParsedBorrowedValue
struct MyValue {
a: String
}
struct MyParsedBorrowedValue<'a> {
_name: &'a str,
_last_name: &'a str
}
fn parse_value(value: &MyValue) -> MyParsedBorrowedValue<'_> {
// (imagine some parsing that borrows from MyValue)
MyParsedBorrowedValue {
_name: &value.a,
_last_name: &value.a
}
}
// Now, imagine I have this trait
trait Predicate<T> {
fn passes(&self, t: &T) -> bool;
}
// I can write a generic combinator like:
struct Not<T, P: Predicate<T>> {
p: P,
_p: std::marker::PhantomData<T>
}
impl<T, P: Predicate<T>> Not<T, P> {
fn new(p: P) -> Not<T, P> { Not { p, _p: std::marker::PhantomData }}
}
impl<T, P: Predicate<T>> Predicate<T> for Not<T, P> {
fn passes(&self, t: &T) -> bool {
!self.p.passes(t)
}
}
// I can write predicates on MyValue. For example:
struct IsMyValueGood {}
impl Predicate<MyValue> for IsMyValueGood {
fn passes(&self, _t: &MyValue) -> bool {
// some processing
true
}
}
// I can also write predicates on MyBorrowedParsedValue
struct IsMyParsedBorrowedValueGood {}
impl<'a> Predicate<MyParsedBorrowedValue<'a>> for IsMyParsedBorrowedValueGood {
fn passes(&self, _t: &MyParsedBorrowedValue<'a>) -> bool {
// some processing ...
false
}
}
// Finally, and this is the most important bit: I want a function that would take a
// Predicate on a "MyParsedBorrowedValue" and transform it into a predicate for a
// MyValue. Something like:
fn map_predicates(p: impl for<'a> Predicate<MyParsedBorrowedValue<'a>>)
-> impl Predicate<MyValue> {
// I believe this is a good use of higher-kinded lifetimes, though I'm not very
// familiar with them.
struct PredicateMapper<P: for<'a> Predicate<MyParsedBorrowedValue<'a>>> {
p: P
}
impl<P: for<'a> Predicate<MyParsedBorrowedValue<'a>>> Predicate<MyValue> for PredicateMapper<P> {
fn passes(&self, value: &MyValue) -> bool {
self.p.passes(&parse_value(value))
}
}
PredicateMapper { p }
}
// This is all good but sadly the following does not compile:
fn compose_predicates() {
// This compiles:
let complex_predicate_1 = map_predicates(IsMyParsedBorrowedValueGood{});
// This doesn't compile!
// Error: implementation of `Predicate` is not general enough
let complex_predicate_2 = map_predicates(Not::new(
IsMyParsedBorrowedValueGood {}
));
}
Link to compiler explorer https://godbolt.org/z/oonfcMdK3
I understand that the Not combinator is not propagating the for <'a> outside, which is what map_predicate needs to do its job. However, I don't know how I would get Not to do that, given that its definition doesn't involve any lifetimes. I guess I could make a custom NotMyParsedBorrowedValue that handles the lifetimes in the correct way, but I would prefer having a single Not combinator that works for all kinds of predicates. Is this possible?

What is the correct syntax to return a function in Rust?

What is the correct syntax to return a function in Rust?
The following code does not compile, thanks.
fn identity<T>(a: T) -> T {
return a;
};
fn right<T>(a: T) -> Fn {
return identity;
};
Here (playground) is a minimal example:
fn identity<T>(a: T) -> T {
return a;
}
fn right<T>(_a: T) -> impl Fn(T) -> T {
return identity;
}
fn main() {
println!("{}", right(0)(42))
}
You need to:
Specify the input argument and output types within the signature, i.e. Fn(T) -> T.
Specify that right's return type implements the trait Fn(T) -> T.
Alternatively, you could also have written the function pointer fn(T) -> T as the return type. Since this is not a trait, you would not need the impl keyword:
fn right<T>(_a: T) -> fn(T) -> T {
return identity;
}
Only fn items and non-capturing closures can be coerced to function pointers, so, while simpler, this will not work in all cases.
This is the best I came up with:
fn identity<T>(a: T) -> T {
return a;
}
fn right<T>() -> &'static dyn Fn(T)->T {
return &identity::<T>;
}
fn main() {
println!("{}", right()(3.1415));
}
playground <-- test it by yourself.
Explanation
&'static dyn Fn(T)->T means that it returns a reference to some object that satisfy the Fn(T)->T trait (because yes Fn(T)->T is indeed a trait, not a type).
Self answer after two answers from others:
I came up with this:
fn identity<T>(a: T) -> T {
a
};
fn right<T, U>(_a: T) -> fn(U) -> U {
identity
};
The return type of right does not have to be identical to input of T of identity.

Pass Generic Function as argument

I would like to be able to pass a generic function to another function (in this case a closure), without losing the "genericness" of the passed function. Since that's a pretty convoluted statement, here's an example:
use std::fmt::Debug;
fn test<F, I: Debug>(gen: F) where F: Fn(fn(I) -> I) -> I {
fn input<I: Debug>(x: I) -> I {
x
}
println!("{:?}", gen(input));
}
fn main() {
test(|input| {
input(10);
input(10.0)
});
}
This will not compile, because the value of input is type inferenced and no longer generic.
Full error:
<anon>:14:15: 14:19 error: mismatched types:
expected `_`,
found `_`
(expected integral variable,
found floating-point variable) [E0308]
<anon>:14 input(10.0)
^~~~
Is such a thing possible in rust?
edit:
Based on the solutions given, I've used the following to solve a similar problem:
#![feature(unboxed_closures)]
#![feature(fn_traits)]
use std::ops::Fn;
use std::ops::Add;
use std::ops::FnMut;
use std::fmt::Debug;
struct Builder;
impl Builder {
pub fn build<A: Add<B>, B: Add<A>>(&self) -> fn(A, B) -> <A as std::ops::Add<B>>::Output {
fn c<A: Add<B>, B: Add<A>>(a: A, b: B) -> <A as std::ops::Add<B>>::Output {
a + b
}
return c;
}
}
impl<A: Add<B>, B: Add<A>> Fn<(A, B)> for Builder {
extern "rust-call" fn call(&self, args: (A, B)) -> <A as std::ops::Add<B>>::Output {
let (a1, a2) = args;
self.build()(a1, a2)
}
}
impl<A: Add<B>, B: Add<A>> FnMut<(A, B)> for Builder {
extern "rust-call" fn call_mut(&mut self, args: (A, B)) -> <A as std::ops::Add<B>>::Output {
let (a1, a2) = args;
self.build()(a1, a2)
}
}
impl<A: Add<B>, B: Add<A>> FnOnce<(A, B)> for Builder {
type Output = <A as std::ops::Add<B>>::Output;
extern "rust-call" fn call_once(self, args: (A, B)) -> <A as std::ops::Add<B>>::Output {
let (a1, a2) = args;
self.build()(a1, a2)
}
}
fn test<F, I: Debug>(gen: F) where F: Fn(Builder) -> I {
let b = Builder;
println!("{:?}", gen(b));
}
fn main() {
test(|builder| {
builder(10, 10);
builder(10.1, 10.0)
});
}
As has been mentioned, unfortunately the call is monomorphized at the call site, so you cannot pass a generic function, you can only pass a monomorphized version of the generic function.
What you can pass, however, is a function builder:
use std::fmt::Debug;
struct Builder;
impl Builder {
fn build<I: Debug>(&self) -> fn(I) -> I {
fn input<I: Debug>(x: I) -> I { x }
input
}
}
fn test<F, T: Debug>(gen: F)
where F: Fn(Builder) -> T
{
let builder = Builder;
println!("{:?}", gen(builder));
}
fn main() {
test(|builder| {
builder.build()(10);
builder.build()(10.0)
});
}
The Builder is able to generate instances of input on demand.
Very interesting question! I'm pretty sure it's not possible like that.
Rust generics work by monomorphizing functions. This means that the Rust compiler will generate the machine code of the function for every concrete type the function is invoked with. Within one call of a function, the generic parameters are fixed. So since you call test exactly once in main, the generic parameters are fixed for that call.
This implies that the closure type is fixed and that the input parameter of the closure has a concrete type, too. The compiler deduces all the types for us, but if we would try to annotate these, we quickly notice that we run into the same problem as the compiler:
test::<_, usize> // we can't ever spell out a closure type, therefore '_'
(|input: fn(usize) -> usize| // we can't have a generic closure right now
{
input(10); // works
input(10.0) // doesn't work
});
This looks a lot like a use case for higher kinded types and generic closures. Both of those features are not available in Rust yet, AFAIK.
However, you can still achieve what you want by using dynamic dispatch:
fn test<F, I: Debug>(gen: F) where F: Fn(fn(Box<Debug>) -> Box<Debug>) -> I {
fn input(x: Box<Debug>) -> Box<Debug> {
x
}
println!("{:?}", gen(input));
}
fn main() {
test(|input| {
input(Box::new(10));
input(Box::new(10.0))
});
}
Of course, this is not as nice as the generic version, but at least it works. Also: if you don't actually need ownership in input, you can change Box<Debug> to &Debug.

What is the difference between generics and associated types?

I was under the impression that these two things were only semantically different.
However, this is possible:
struct Foo;
trait Bar<T> {
fn resolve(&self) -> T;
}
impl Bar<isize> for Foo {
fn resolve(&self) -> isize {
return 0isize;
}
}
impl Bar<usize> for Foo {
fn resolve(&self) -> usize {
return 1usize;
}
}
#[test]
fn test_foo() {
let foo = Foo;
assert!((&foo as &Bar<isize>).resolve() == 0isize);
assert!((&foo as &Bar<usize>).resolve() == 1usize);
}
While this is not:
struct Foo;
trait Bar {
type T;
fn resolve(&self) -> Self::T;
}
impl Bar for Foo {
type T = isize;
fn resolve(&self) -> isize {
return 0isize;
}
}
impl Bar for Foo {
type T = usize;
fn resolve(&self) -> usize {
return 1usize;
}
}
#[test]
fn test_foo() {
let foo = Foo;
assert!((&foo as &Bar<T = isize>).resolve() == 0isize);
assert!((&foo as &Bar<T = usize>).resolve() == 1isize);
}
It generates:
<anon>:8:1: 13:2 error: conflicting implementations for trait `Bar` [E0119]
<anon>: 8 impl Bar for Foo {
<anon>: 9 type T = isize;
<anon>:10 fn resolve(&self) -> isize {
<anon>:11 return 0isize;
<anon>:12 }
<anon>:13 }
Am I missing something?
Is there a special syntax for what I'm trying to achieve, or is there really a... technical... distinction between a generic and an associated type?
Is there some circumstance in which an associated type has a tangible (rather than purely code prettiness) benefit over using a generic?
I'll repeat my comment: it is true that type parameters and associated types are only semantically different. However, that's the main point why they are both present in the language - they do their own separate jobs, so it is not "just" semantic difference, it is the whole reason for their existence as a separate thing from type parameters.
Note that I do not even touch syntactic differences. Of course it is absolutely natural that there are syntactic differences. These are separate features after all; if they had no syntactic differences, then how you would distinguish between them? Their syntactic difference is closely tied to the semantic difference, because the way associated types are defined makes it clear that they have "output" position, compared to "input" position of type parameters, but technically both type parameters and associated types (and also the implicit Self, parameter, by the way) are the same thing.
For anyone else who finds this question, there is also another technical distinction between type parameters and associated types as well.
If you attempt to implement a trait with an associated type you may see the error:
src/lib.rs:10:1: 15:2 error: the impl does not reference any types
defined in this crate; only traits defined in the current crate can
be implemented for arbitrary types [E0117]
If you have traits exported in a crate bar:
pub trait BarParam<TRtn> {
fn bar() -> TRtn;
}
pub trait BarAssoc {
type TRtn;
fn bar() -> Self::TRtn;
}
You will find that a crate importing these traits will only be able to implement:
impl<'a> BarParam<Foo> for &'a str {
fn bar() -> Foo {
return Foo;
}
}
While attempting to implement:
impl<'a> BarAssoc for &'a str {
type TRtn = Foo;
fn bar() -> Foo {
return Foo;
}
}
Will result in the error above.
Frankly I'm not really sure what's going on here, so if you do, by all means add a comment or another answer; but this is a tangible reason to avoid associated types when you're writing a crate.

Resources