I was experimenting with const generics when this strange error came out: error: unconstrained generic constant. What does it mean?
Maybe I should describe what was I tried to do before actual code - I wanted to treat types as numbers, using Lisp-like Cons and Nil.
Here's an example:
use core::marker::PhantomData;
struct Nil;
struct Cons <N> (PhantomData <N>);
So '1' is Cons <Nil>, '2' - Cons <Cons <Nil>>, etc.
Then I tried to implement extracting normal number from this.
trait Len {
const N: usize;
}
impl <N: Len> Len for Cons <N> {
const N: usize = 1 + N::N;
}
impl Len for Nil {
const N: usize = 0;
}
And it works.
Then I started doing actual job: my true task was not to just experiment with generic types, but to implement mathematical vecs, just like(maybe you know) in shaders.
So I tried to implement such powerful constructor:
vec3 i = vec3(1.0, 1.0, 1);
vec4 v = vec4(i);
I have decided to treat any value as 'Piece' and then just compound pieces together.
trait Piece <T> {
type Size: Len;
fn construct(self) -> [T; Self::Size::N];
}
No problems so far. Next step is to define few auxiliary traits(since rust does not yet support negative bounds):
pub auto trait NotTuple {}
impl <T> !NotTuple for (T,) {}
pub auto trait NotList {}
impl <T, const N: usize> !NotList for [T; N] {}
I am using nightly rust, so few #![feature]-s is not a problem.
Then, we can use it:
type One = Cons <Nil>;
impl <T: Copy + From <U>, U: Copy + NotTuple + NotList> Piece <T> for U {
type Size = One;
fn construct(self) -> [T; Self::Size::N] {
[T::from(self)]
}
}
This one constructs piece from an argument.
Everything is still good.
impl <T: Copy, U: Piece <T>> Piece <T> for (U,) {
type Size = U::Size;
fn construct(self) -> [T; Self::Size::N] {
self.0.construct()
}
}
And this is where problem occurs. Compiler says that Self::Size::N is an unconstrained generic constant, and tries to help with this: try adding a 'where' bound using this expression: 'where [(); Self::Size::N]:', but this is just useless.
Can anyone explain me what is going on and how to fix this issue?
Related
Given a matrix type in Rust using const generic parameters, something like this:
pub struct Mat<T, const R: usize, const C: usize>
{
m: [[T; C]; R],
}
I am aware that specializations are not available (yet, and not for this type of
specialization it seems?), but it seems like it is possible to implement some
'specializations' for specific instances of this type, e.g.:
impl<T> Mat<T, 2, 2>
{
pub fn invert(self) -> Self
where T: From<f32> + Clone + std::ops::Neg<Output=T> + std::ops::Sub<T, Output = T> +
std::ops::Mul<T, Output = T> + std::ops::Div<T, Output = T>
{
let r = T::from(1.0) / self.clone().determinant();
Mat::new([[ self[1][1]*r.clone(), -self[0][1]*r.clone()],
[-self[1][0]*r.clone(), self[0][0]*r]])
}
pub fn determinant(self) -> T
where T: std::ops::Sub<T, Output = T> + std::ops::Mul<T, Output = T>
{
self[0][0]*self[1][1] - self[0][1]*self[1][0]
}
}
Similar 'specializations' can be implemented for 3x3 and 4x4 matrices.
However, at some point I would like to also implement a generalized
determinant/inverse, something like this:
impl<T, const N: usize> Mat<T, N, N>
{
/// Generalized matrix inversion.
pub fn gen_invert(self) -> Self
{
// TODO: determinant(), matrix_minor(), cofactor(), adjugate()
Mat::default()
}
/// Generalized matrix determinant.
pub fn gen_det(self) -> T
{
match N
{
1 => self.determinant(), // <- Wrong type Mat<T, N, N>, not Mat<T, 1, 1>.
// 2 => // Same as above.
_ => general_fn(),
}
}
}
This turned out to be hard however, since there does not seem to be any way to
cast or even transmute a type of Mat<T, N, N> to Mat<T, 1, 1>, even though we
know that the sizes are correct, given that is done on a const variable under
an appropriate match case. Is there some way to accomplish the above without an
expensive from() function that manually creates a Mat<T, 1, 1> from the Mat<T,
N, N>?
Additionally, is there some way to avoid renaming the generalized versions of
these functions? I tried to do that using traits, similar to this question, but
since all functions have the same name this does not appear to work for this
case.
(There are even more complications with this though, since computing minor
matrices requires arithmetic on const generics and that is only in nightly Rust
right now, but that is beyond the scope of this question.)
I've recently taken on learning Rust and I'm trying to write a small expression evaluator. I've been practicing Rust for a few days now and thought this task would be cool to work with Rust's Traits. What I tried to do is make Sum & Number structs implement Expression trait, so that I could express (pun unintended) (1 + 2) as an expression where left and right hand sides are expressions too.
I've stumbled onto the problem that you can't just use Traits as properties' types, so you instead should use &dyn Trait or Box in the Book. Following this notion a rewrote it and now it compiles, but I can't get access to values inside Sum.
Here's my code:
trait Expression {}
#[derive(Debug)]
struct Number {
pub val: i32
}
impl Expression for Number {}
struct Sum {
pub left: Box<dyn Expression>,
pub right: Box<dyn Expression>
}
impl Expression for Sum {}
fn main() {
let e = Sum{ left: Box::new(Number{ val: 2}),
right: Box::new(Number{ val: 2})
};
let sum = (2 + 2);
println!("{:#?}", sum);
}
What I want to be able to do is get to Number's value:
e.left.val
and use nested constuctions like:
Sum{Sum{Number, Sum{Number, Number}}, Number}
I also tried to make explicit cast to Number:
let val = (e.left as Number).val;
But it fails with an error:
non-primitive cast: std::boxed::Box<(dyn Expression + 'static)> as Number
note: an as expression can only be used to convert between primitive types. Consider using the From trait.
Sorry for any language mistakes or messy explanation, English is not my first language.
I'm not an experienced programmer and very new to Rust so I would really appreciate any help, thanks!
Rust doesn't let you cast non primitive types.
Reference:
https://doc.rust-lang.org/rust-by-example/types/cast.html
I think what you're trying to do is this (complete code in the playground):
trait Expression {
fn evaluate(&self) -> i32;
}
impl Expression for Number {
fn evaluate(&self) -> i32 {
self.val
}
}
impl Expression for Sum {
fn evaluate(&self) -> i32 {
self.left.evaluate() + self.right.evaluate()
}
}
I'm a complete newbie in Rust and I'm trying to get some understanding of the basics of the language.
Consider the following trait
trait Function {
fn value(&self, arg: &[f64]) -> f64;
}
and two structs implementing it:
struct Add {}
struct Multiply {}
impl Function for Add {
fn value(&self, arg: &[f64]) -> f64 {
arg[0] + arg[1]
}
}
impl Function for Multiply {
fn value(&self, arg: &[f64]) -> f64 {
arg[0] * arg[1]
}
}
In my main() function I want to group two instances of Add and Multiply in a vector, and then call the value method. The following works:
fn main() {
let x = vec![1.0, 2.0];
let funcs: Vec<&dyn Function> = vec![&Add {}, &Multiply {}];
for f in funcs {
println!("{}", f.value(&x));
}
}
And so does:
fn main() {
let x = vec![1.0, 2.0];
let funcs: Vec<Box<dyn Function>> = vec![Box::new(Add {}), Box::new(Multiply {})];
for f in funcs {
println!("{}", f.value(&x));
}
}
Is there any better / less verbose way? Can I work around wrapping the instances in a Box? What is the takeaway with trait objects in this case?
Is there any better / less verbose way?
There isn't really a way to make this less verbose. Since you are using trait objects, you need to tell the compiler that the vectors's items are dyn Function and not the concrete type. The compiler can't just infer that you meant dyn Function trait objects because there could have been other traits that Add and Multiply both implement.
You can't abstract out the calls to Box::new either. For that to work, you would have to somehow map over a heterogeneous collection, which isn't possible in Rust. However, if you are writing this a lot, you might consider adding helper constructor functions for each concrete impl:
impl Add {
fn new() -> Add {
Add {}
}
fn new_boxed() -> Box<Add> {
Box::new(Add::new())
}
}
It's idiomatic to include a new constructor wherever possible, but it's also common to include alternative convenience constructors.
This makes the construction of the vector a bit less noisy:
let funcs: Vec<Box<dyn Function>> = vec!(Add::new_boxed(), Multiply::new_boxed()));
What is the takeaway with trait objects in this case?
There is always a small performance hit with using dynamic dispatch. If all of your objects are the same type, they can be densely packed in memory, which can be much faster for iteration. In general, I wouldn't worry too much about this unless you are creating a library crate, or if you really want to squeeze out the last nanosecond of performance.
Update: This bug has been fixed by https://github.com/rust-lang/rust/pull/23673 . The code below now works.
In math and numerical programming, it is expected that complex numbers interoperate seamlessly with real (floating point) values. Is it possible in Rust to define a struct Complex<T: Float> that allows symmetric math operations involving values of type T?
For example, one can define the operator * for inputs (Complex<T>, Complex<T>) and (Complex<T>, T) as follows:
use std::ops::Mul;
use std::num::Float;
#[derive(Copy, Debug)]
pub struct Complex<T: Float> {
pub re: T, pub im: T
}
impl<T: Float> Complex<T> {
pub fn new(re: T, im: T) -> Complex<T> {
Complex { re: re, im: im }
}
}
impl<T: Float> Mul<Complex<T>> for Complex<T> {
type Output = Complex<T>;
fn mul(self, other: Complex<T>) -> Complex<T> {
Complex::new(self.re * other.re - self.im * other.im,
self.re * other.im + self.im * other.re)
}
}
impl<T: Float> Mul<T> for Complex<T> {
type Output = Complex<T>;
fn mul(self, other: T) -> Complex<T> {
Complex::new(self.re * other, self.im * other)
}
}
Is it possible to overload * to also work on the inputs (T, Complex<T>)? For example, the following doesn't work:
impl Mul<Complex<f64>> for f64 {
type Output = Complex<f64>;
fn mul(self, other: Complex<f64>) -> Complex<f64> {
Complex::new(self * other.re, self * other.im)
}
}
fn main() {
let x = Complex::new(1.0, 1.0);
let y = x*x;
let z = x*4.0;
let w = 4.0*x;
}
I get the error message:
error: mismatched types:
expected `_`,
found `Complex<_>`
(expected floating-point variable,
found struct `Complex`) [E0308]
src/main.rs:61 let w = 4.0*x;
^
In Scala, one might work around this problem with an implicit conversion from T to Complex<T>. Are there similar tricks in Rust? Is there a better way to define an efficient, generalized * operation? Thanks.
This should be allowed, but there's an outstanding issue that prevents built-in types (u8, f32, etc) from being used on the left-hand side of the operation when a custom implementation is in play.
The suggested workaround for now is to put the custom type on the left-hand side and the built-in type on the right.
Note: This question was asked before Rust's first stable release. There have been lots of changes since and the syntax used in the function is not even valid anymore. Still, Shepmaster's answer is excellent and makes this question worth keeping.
Finally unboxed closures have landed, so I am experimenting with them to see what you can do.
I have this simple function:
fn make_adder(a: int, b: int) -> || -> int {
|| a + b
}
However, I get a missing lifetime specifier [E0106] error. I have tried to fix this by changing the return type to ||: 'static -> int, but then I get another error cannot infer an appropriate lifetime due to conflicting requirements.
If I understand correctly, the closure is unboxed so it owns a and b. It seems very strange to me that it needs a lifetime. How can I fix this?
As of Rust 1.26, you can use impl trait:
fn make_adder(a: i32) -> impl Fn(i32) -> i32 {
move |b| a + b
}
fn main() {
println!("{}", make_adder(1)(2));
}
This allows returning an unboxed closure even though it is impossible to specify the exact type of the closure.
This will not help you if any of these are true:
You are targeting Rust before this version
You have any kind of conditional in your function:
fn make_adder(a: i32) -> impl Fn(i32) -> i32 {
if a > 0 {
move |b| a + b
} else {
move |b| a - b
}
}
Here, there isn't a single return type; each closure has a unique, un-namable type.
You need to be able to name the returned type for any reason:
struct Example<F>(F);
fn make_it() -> Example<impl Fn()> {
Example(|| println!("Hello"))
}
fn main() {
let unnamed_type_ok = make_it();
let named_type_bad: /* No valid type here */ = make_it();
}
You cannot (yet) use impl SomeTrait as a variable type.
In these cases, you need to use indirection. The common solution is a trait object, as described in the other answer.
It is possible to return closures inside Boxes, that is, as trait objects implementing certain trait:
fn make_adder(a: i32) -> Box<dyn Fn(i32) -> i32> {
Box::new(move |b| a + b)
}
fn main() {
println!("{}", make_adder(1)(2));
}
(try it here)
There is also an RFC (its tracking issue) on adding unboxed abstract return types which would allow returning closures by value, without boxes, but this RFC was postponed. According to discussion in that RFC, it seems that some work is done on it recently, so it is possible that unboxed abstract return types will be available relatively soon.
The || syntax is still the old boxed closures, so this doesn't work for the same reason it didn't previously.
And, it won't work even using the correct boxed closure syntax |&:| -> int, since it is literally is just sugar for certain traits. At the moment, the sugar syntax is |X: args...| -> ret, where the X can be &, &mut or nothing, corresponding to the Fn, FnMut, FnOnce traits, you can also write Fn<(args...), ret> etc. for the non-sugared form. The sugar is likely to be changing (possibly something like Fn(args...) -> ret).
Each unboxed closure has a unique, unnameable type generated internally by the compiler: the only way to talk about unboxed closures is via generics and trait bounds. In particular, writing
fn make_adder(a: int, b: int) -> |&:| -> int {
|&:| a + b
}
is like writing
fn make_adder(a: int, b: int) -> Fn<(), int> {
|&:| a + b
}
i.e. saying that make_adder returns an unboxed trait value; which doesn't make much sense at the moment. The first thing to try would be
fn make_adder<F: Fn<(), int>>(a: int, b: int) -> F {
|&:| a + b
}
but this is saying that make_adder is returning any F that the caller chooses, while we want to say it returns some fixed (but "hidden") type. This required abstract return types, which says, basically, "the return value implements this trait" while still being unboxed and statically resolved. In the language of that (temporarily closed) RFC,
fn make_adder(a: int, b: int) -> impl Fn<(), int> {
|&:| a + b
}
Or with the closure sugar.
(Another minor point: I'm not 100% sure about unboxed closures, but the old closures certainly still capture things by-reference which is another thing that sinks the code as proposed in the issue. This is being rectified in #16610.)
Here's how to implement a closure based counter:
fn counter() -> impl FnMut() -> i32 {
let mut value = 0;
move || -> i32 {
value += 1;
return value;
}
}
fn main() {
let mut incre = counter();
println!("Count 1: {}", incre());
println!("Count 2: {}", incre());
}