How can I simplify multiple uses of BigInt::from()? - rust

I wrote a program where I manipulated a lot of BigInt and BigUint values and perform some arithmetic operations.
I produced code where I frequently used BigInt::from(Xu8) because it is not possible to directly add numbers from different types (if I understand correctly).
I want to reduce the number of BigInt::from in my code. I thought about a function to "wrap" this, but I would need a function for each type I want to convert into BigInt/BigUint:
fn short_name(n: X) -> BigInt {
return BigInt::from(n)
}
Where X will be each type I want to convert.
I couldn't find any solution that is not in contradiction with the static typing philosophy of Rust.
I feel that I am missing something about traits, but I am not very comfortable with them, and I did not find a solution using them.
Am I trying to do something impossible in Rust? Am I missing an obvious solution?

To answer this part:
I produced code where I frequently used BigInt::from(Xu8) because it is not possible to directly add numbers from different types (if I understand correctly).
On the contrary, if you look at BigInt's documentation you'll see many impl Add:
impl<'a> Add<BigInt> for &'a u64
impl Add<u8> for BigInt
and so on. The first allows calling a_ref_to_u64 + a_bigint, the second a_bigint + an_u8 (and both set OutputType to be BigInt). You don't need to convert these types to BigInt before adding them! And if you want your method to handle any such type you just need an Add bound similar to the From bound in Frxstrem's answer. Of course if you want many such operations, From may end up more readable.

The From<T> trait (and the complementary Into<T> trait) is what is typically used to convert between types in Rust. In fact, the BigInt::from method comes from the From trait.
You can modify your short_name function into a generic function with a where clause to accept all types that BigInt can be converted from:
fn short_name<T>(n: T) -> BigInt // function with generic type T
where
BigInt: From<T>, // where BigInt implements the From<T> trait
{
BigInt::from(n)
}

Related

Object safe generic without type erasure

In the trait Extendable below, I'd like to make app generic where it currently uses the concrete type i32.
At first blush, you'd think to use a generic type but doing so while keeping Extendable object safe isn't easy.
trait Isoextender {
type Input;
type Output;
fn forward(&self, v: Self::Input) -> Self::Output;
fn backward(&self, v: Self::Output) -> Self::Input;
}
trait Extendable {
type Item;
fn app(
&self,
v: &dyn Isoextender<Input = Self::Item, Output = i32>,
) -> Box<dyn Extendable<Item = i32>>;
}
There's a (really neat) type erasure trick (link) I can use with std::Any but then I'm losing type information.
This is one of those things that feels like it should be possible from my understanding of how Rust works but which simply might not be. I do see there's an issue with size. Clearly rust needs to know the size of the associated type Item, but I don't see how to solve with with references/pointers in a way that's both object safe and keeps the type information.
Is it the case that:
I am missing something and it's actually possible?
This is not possible today, but it may become possible in the future?
This is not likely to be possible ever?
Update:
So I suppose a part of the issue here is that I feel like the following is a generic function that has only 1 possible implementation. You should only have to compile this once.
fn pointer_identity<T>(v: &T) -> &T {
v
}
It feels like I should be able to put this function into a vtable, but still somehow express that it is generic. There are a whole class of easily identifiable functions that effectively act this way. Interactions between trait objects often act this way. It's all pointers to functions where the types don't matter except to be carried forward.
I found some document ion that may answer my question.
Currently, the compiler has two concepts surrounding Generic code, only one of which seems to be surfaced in the type system (link).
It sounds like this may be possible some day, but not currently expressible with Rust.
Monomorphization
The compiler stamps out a different copy of the code of a generic function for each concrete type needed.
Polymorphization
In addition to MIR optimizations, rustc attempts to determine when fewer copies of functions are necessary and avoid making those copies - known as "polymorphization".
As a result of polymorphization, items collected during monomorphization cannot be assumed to be monomorphic.
It is intended that polymorphization be extended to more advanced cases, such as where only the size/alignment of a generic parameter are required.

Restrict a generic Type to primative number types [duplicate]

This question already has answers here:
Is there any way to restrict a generic type to one of several types?
(2 answers)
Closed 3 years ago.
We can restrict a type to one or more traits by where clause.
My questions are:
Is it possible to restrict a type to just primitive number types?
How?
No.
To use a parametric type, you need the trait to define the valid operations you want to call on it. So you need a trait (or more) with all the operations you want to call.
The “primitive” types in Rust are not special in any way. They define their operators via the traits from std::ops (though obviously using compiler intrinsics) just like any “non-primitive” numberic types.
In fact, the boundary between “primitive” and “non-primitive” numeric types is even somewhat blurred, since for targets that lack an FPU, the standard library may be implementing floating point types in code, and in Rust it can do it transparently to the user.
So really, there is no such thing as primitive number types. Number types are defined by providing whatever operators you need to call. So just restrict your type by the std::ops traits.
Since primitives are not trait types you cannot use as boundary to restrict a generic type. But you can directly implement for a specific type:
struct Struct<T>(T);
trait Printer {
fn print(&self);
}
impl Printer for Struct<i32> {
fn print(&self) {
println!("Printing for i32 value: {}", self.0);
}
}
fn main() {
let x = Struct(15_i32);
let _z = Struct(14.2_f64);
x.print();
//_z.print();//compile error
}
Playground
Alternatively you can use Borrow<S> trait as trick, you can restrict your generic parameter as like below : ( T: Borrow<S> means T can be borrowed as S ) .
impl<T> Printer for Struct<T>
where
T: Borrow<f64> + Debug,
{
fn print(&self) {
println!("Printing for f64 value: {:?}", self.0);
}
}
Playground
But since you can implement Borrow<f64> for any type, this kind of restriction may not be considered as strict.
Also just for the numeric primitives you can use traits from num-traits crate like ToPrimitive AsPrimitive
If you think about traits as compile time duck typing, then a better question would be: what are the exact traits you are looking for in a number? Most of the operations on them could be defined as trait constraints on your types, see: the standard operator traits.
Even if you would define a trait in an external crate and implement the behaviour for specific types only in that external crate, thinking that the trait implementation rules will help you there (i.e. a trait can only be implemented to a type if either the trait or the type or both are in your current crate) would still not limit anyone to implement your trait for their own types.
Therefore, I see no other option but to implement the behaviours without generics for each primitive number type. To avoid code duplication, I would probably use macros for this -- after all, if you think about it in some ways you would manually do what the compiler does while it monomorphises your generic code.
That being said I see no reason to limit behaviours to numbers but to certain traits and I would rely on them as I described it in the first paragraph.

Are operators in core really defined circularly?

We can implement the traits in core::ops to define the behavior of operators for our types. The traits themselves are annotated with #[lang =...] attributes so the compiler knows which traits and operators belong together.
For example, the Add implementation for primitive types looks like this (macro manually expanded and simplified from here):
impl Add for i32 {
type Output = i32;
fn add(self, other: i32) -> i32 {
self + other
}
}
To my surprise, the implementation uses the + operator internally, which presumably calls self.add(other), resulting in an infinite recursion. Obviously, things do not happen like this because expressions like 3 + 4 (assuming no constant folding) work perfectly fine.
Now consider this naive implementation of the Add trait:
use std::ops::Add;
struct Foo;
impl Add for Foo {
type Output = Foo;
fn add(self, other: Foo) -> Foo {
self + other
}
}
fn main() {
let two_foo = Foo + Foo;
}
The compiler warns that function cannot return without recurring and running this program in Debug mode properly stops with fatal runtime error: stack overflow.
How does the compiler know how to add two numbers without falling into a recursive loophole?
How does the compiler know to add two numbers without falling into a recursive loophole?
Because the compiler is the compiler, and the compiler knows it doesn't need an Add implementation to add two numbers. If it's doing constant folding, it just adds them. If it's generating code, it tells LLVM to add them at runtime.
Those Add implementations aren't there to tell the compiler how to add numbers, they're to implement Add for numbers so that user code can add numbers via the Add trait just like any user-defined type. If those implementations didn't exist, then you wouldn't be able to add numbers in generic methods, because they wouldn't implement Add.
To put it another way: Add is what the compiler uses when it doesn't otherwise know how to add things. But it already knows how to add numbers, so it doesn't need them. They're provided for consistency with other types.
The implementations of Add that rely on the addition operator + in the end need to point to operations on primitives (eg. integers) and arithmetic operations on those are implemented using compiler built-ins.
What is more, the primitives themselves are compiler built-ins as well - note that you won't be able to find their sources in the std documentation.
The bottom line is that primitive types don't actually need the code provided by the implementations of Add and other artithmetic operators' traits at all - these functionalities are provided by the compiler's intrinsics. Their trait implementations are provided for the purposes of generics.

Dynamically inferring the type of a string

Rust newbie here. What would be a good way to go about dynamically inferring the most probably type given a string? I am trying to code a function that given a string returns the most possible type but I have no idea where to start. In Python I would probably use a try-except block. This is what I would expect to have:
"4" -> u32 (or u64)
"askdjf" -> String
"3.2" -> f64
and so on? I know that some strings can be assigned to several possible types so the problem is not well defined but I am only interested in the general philosophy on how to solve the problem efficiently in rust.
There is a parse method on string slices (&str) that attempts to parse a string as a particular type. You'll have to know the specific types you're ready to handle, though. The parse method can return values of any type that implements FromStr.
fn main() {
if let Ok(i) = "1".parse::<u32>() {
println!("{}", i);
}
if let Ok(f) = "1.1".parse::<f64>() {
println!("{}", f);
}
}
Note that the ::<T> part is only necessary if the compiler is unable to infer what type you're trying to parse into (you'll get a compiler error in that case).
I am trying to code a function that given a string returns the most possible type but I have no idea where to start.
First of all: Rust is statically typed which means that a function returns one and only one type, so you can't just return different types, like in dynamically typed languages. However, there are ways to simulate dynamic typing -- namely two (that I can think of):
enum: If you have a fixed number of possible types, you could define an enum with one variant per type, like this:
enum DynType {
Integer(i64),
Float(f32),
String(String),
}
fn dyn_parse(s: &str) -> DynType {
...
}
You can read more on enums in this and the following Rust book chapter.
There is a trait in the standard library designed to simulate dynamic typing: Any. There is more information here. Your code could look like this:
fn dyn_parse(s: &str) -> Box<Any> {
...
}
You can't return trait objects directly, so you have to put it in a Box.
Keep in mind that both possibilities require the user of your function to do additional dispatch. Since Rust is statically typed, you can't do the things you are used to in a dynamically typed language.
Maybe you should try to solve your problems in a different way that makes more sense in the statically typed world.
About the implementation part: Like Francis Gagné said, there is parse which tries to parse a string as a type the programmer specifies. You could of course just chain those parse calls with different types and take the first one that succeeds. But this might not be what you want and maybe not the fastest implementation.
Of course you should first think of exact rules what string should parse as what type. After that you could, for example, build a finite state machine that detects the type of the string. Doing that properly could be a bit tricky though.

How do I call a function through a member variable?

Toying with Rust, I'm extracting some code into a class. To keep it self-contained but separate functionality, I want to hang onto a callback function and call it later. To keep it simple, including skipping the obvious fn new(), we have something like:
pub struct Toy {
go: fn(count: i16) -> String,
}
impl Toy {
fn lets_go(&mut self, n: i16) -> String {
self.go(n)
}
}
Building gives me...
...path.../src/toy.rs:7:14: 7:19 error: type `&mut toy::Toy` does not implement any method in scope named `go`
...path.../src/toy.rs:7 self.go(n)
Presumably, there's a special syntax (or entirely different construct) that makes sense of the self.go() call, but I don't see examples or descriptions of comparable situations in any of the documentation, so I'd appreciate any direction.
Obviously, .go could be of a functor-like class, but that doesn't seem very idiomatic for Rust.
foo.bar(...) is always parsed as a method call, it never looks for fields. This avoids ambiguity, especially with traits. One can force it to be a field access by separating the call and the field access into two distinct expressions, for example,
let f = self.go;
f(n)
Or, better, just (self.go)(n).
Issue #2392 covers improving these diagnostics.

Resources