How to implement idiomatic operator overloading for values and references in Rust? - operator-overloading

When implementing a primitive fixed-size vector type (float2 for example), I want to support the Add and Sub traits. Later, I will want to support Mul and *Assign.
Looking up the documentation and other examples, I came up with this:
use std::ops::{Add, Sub};
#[derive(Copy, Clone)]
struct float2(f64, f64);
impl Add for float2 {
type Output = float2;
fn add(self, _rhs: float2) -> float2 {
float2(self.0 + _rhs.0, self.1 + _rhs.1)
}
}
impl Sub for float2 {
type Output = float2;
fn sub(self, _rhs: float2) -> float2 {
float2(self.0 - _rhs.0, self.1 - _rhs.1)
}
}
This works for basic examples, however I found in practice I would often end up with references passed in as arguments as well as local float2's on the stack.
To mix these I needed to either:
De-reference variables (OK but makes code a little less readable).
Declare operator overloading combinations of references too.
Example:
impl<'a, 'b> Add<&'b float2> for &'a float2 {
type Output = float2;
fn add(self, _rhs: &'b float2) -> float2 {
float2(self.0 + _rhs.0, self.1 + _rhs.1)
}
}
impl<'a> Add<float2> for &'a float2 {
type Output = float2;
fn add(self, _rhs: float2) -> float2 {
float2(self.0 + _rhs.0, self.1 + _rhs.1)
}
}
impl<'b> Add<&'b float2> for float2 {
type Output = float2;
fn add(self, _rhs: &'b float2) -> float2 {
float2(self.0 + _rhs.0, self.1 + _rhs.1)
}
}
/*... and again for Sub */
While this allows to write expressions without de-referencing. it becomes quite tedious to enumerate each combinations, especially when adding more operations & types (float3, float4...).
Is there a generally accepted way to...
Automatically coerce types for operator overloading?
Use macros or some other feature of the language to avoid tedious repetition?
Or is it expected that developers either:
Explicitly access variables as references as needed.
Explicitly de-reference variables as needed.
Write a lot of repetitive operator overloading functions.
Note, I'm currently a beginner, I've checked some quite advanced math libraries in Rust, they're way over my head, while I could use them - I would like to understand how to write operator overloading for my own types.

The great thing about Rust is that it's open source. This means you can see how the authors of the language have solved a problem. The closest analogue is primitive integer types:
macro_rules! add_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
impl Add for $t {
type Output = $t;
#[inline]
fn add(self, other: $t) -> $t { self + other }
}
forward_ref_binop! { impl Add, add for $t, $t }
)*)
}
forward_ref_binop is defined as:
macro_rules! forward_ref_binop {
(impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> $imp<$u> for &'a $t {
type Output = <$t as $imp<$u>>::Output;
#[inline]
fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
$imp::$method(*self, other)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> $imp<&'a $u> for $t {
type Output = <$t as $imp<$u>>::Output;
#[inline]
fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
$imp::$method(self, *other)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b> $imp<&'a $u> for &'b $t {
type Output = <$t as $imp<$u>>::Output;
#[inline]
fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
$imp::$method(*self, *other)
}
}
}
}
It's certainly valid to write wrapper implementations of the traits for references that simply dereference and call the value-oriented version.

I advise you to use the impl_os crate for that purpose, see that other answer that I wrote.

Related

Is is possible to callAsFunction() variable that is Any?

Recently I have encountered a need of creating an Array of Functions. Unfortunately, Swift language does not provide a top level type for functions, but instead they must be declared by their specific signature (...)->(...). So I tried to write a wrapper that can hold any function and later specialize it to hold only closures having Void return type and any number of arguments.
struct AnyFunction {
let function: Any
init?(_ object: Any){
switch String(describing: object){
case let function where function == "(Function)":
self.function = object
default:
return nil
}
}
func callAsFunction(){
self.function()
}
}
As I was progressing, I have found out that it is not trivial and possibly requires some hacks with introspection, but I failed to find solution, despite of my attempt. The Compiler messaged:
error: cannot call value of non-function type 'Any'
So how would you make this trick that is, to clarify, to define an Object that can hold any functional type?
Clarification:
What I would prefer is defining something like:
typealias SelfSufficientClosure = (...)->Void
var a, b, c = 0
let funcs = FunctionSequence
.init(with: {print("Hi!")}, {a in a + 3}, {b in b + 3}, { a,b in c = a + b})
for f in funcs { f() }
print([a, b, c])
//outputs
//"Hi"
//3, 3, 6
PS This question has relation to this one (Any or a trouble with sequence of functions)
A function is a mapping from inputs to outputs. In your examples, your inputs are void (no inputs), and your outputs are also void (no outputs). So that kind of function is precisely () -> Void.
We can tell that's the right type because of how you call it:
for f in funcs { f() }
You expect f to be a function that takes no inputs and returns no outputs, which is exactly the definition of () -> Void. We can get exactly the input and output you expect by using that type (and cleaning up a few syntax errors):
var a = 0, b = 0, c = 0
let funcs: [() -> Void] = [{print("Hi!")}, {a = a + 3}, { b = b + 3}, { c = a + b}]
for f in funcs { f() }
print(a, b, c, separator: ",")
//outputs
//Hi!
//3, 3, 6
When you write a closure like {a in a + 3}, that doesn't mean "capture a" (which I believe you are expecting). It means "This is a closure that accepts a parameter that will be called a (completely unrelated to the global variable of the same name) and returns that value plus 3." If that's what you meant, then when you called f(), you would need to pass it something and do something with the return value.
You can use an enum to put various functions into the Array and then extract the functions with a switch.
enum MyFuncs {
case Arity0 ( Void -> Void )
case Arity2 ( (Int, String) -> Void)
}
func someFunc(n:Int, S:String) { }
func boringFunc() {}
var funcs = Array<MyFuncs>()
funcs.append(MyFuncs.Arity0(boringFunc))
funcs.append( MyFuncs.Arity2(someFunc))
for f in funcs {
switch f {
case let .Arity0(f):
f() // call the function with no arguments
case let .Arity2(f):
f(2,"fred") // call the function with two args
}
}

Using macros, how to get unique names for struct fields?

Suppose I have some macro invoked as such:
my_macro!(Blah, (a, b, c));
And it outputs something like this:
struct Blah {
a: i32,
b: i32,
c: i32
}
impl Blah {
fn foo() -> i32 {
a + b + c
}
}
(artificial example)
These fields will be private to the struct, but I need to allow redefinitions. So, the input
my_macro!(Blah, (a, b, c, a));
Will generate something like:
struct Blah {
a1: i32,
b: i32,
c: i32,
a2: i32
}
impl Blah {
fn foo() -> i32 {
a1 + b + c + a2
}
}
The naming scheme doesn't need to follow any logical pattern.
Is this possible?
My mashup crate provides a way for you to expand my_macro!(Blah, (a, b, c, a)) into fields x_a, xx_b, xxx_c, xxxx_d if that naming convention would work for you. We prepend an additional x for each field, followed by an underscore, followed by the original field name so that way no fields can end up with conflicting names. This approach works with any Rust version >= 1.15.0.
#[macro_use]
extern crate mashup;
macro_rules! my_macro {
($name:ident, ($($field:ident),*)) => {
my_macro_helper!($name (x) () $($field)*);
};
}
macro_rules! my_macro_helper {
// In the recursive case: append another `x` into our prefix.
($name:ident ($($prefix:tt)*) ($($past:tt)*) $next:ident $($rest:ident)*) => {
my_macro_helper!($name ($($prefix)* x) ($($past)* [$($prefix)* _ $next]) $($rest)*);
};
// When there are no fields remaining.
($name:ident ($($prefix:tt)*) ($([$($field:tt)*])*)) => {
// Use mashup to define a substitution macro `m!` that replaces every
// occurrence of the tokens `"concat" $($field)*` in its input with the
// resulting concatenated identifier.
mashup! {
$(
m["concat" $($field)*] = $($field)*;
)*
}
// Invoke the substitution macro to build a struct and foo method.
// This expands to:
//
// pub struct Blah {
// x_a: i32,
// xx_b: i32,
// xxx_c: i32,
// xxxx_a: i32,
// }
//
// impl Blah {
// pub fn foo(&self) -> i32 {
// 0 + self.x_a + self.xx_b + self.xxx_c + self.xxxx_a
// }
// }
m! {
pub struct $name {
$(
"concat" $($field)*: i32,
)*
}
impl $name {
pub fn foo(&self) -> i32 {
0 $(
+ self."concat" $($field)*
)*
}
}
}
};
}
my_macro!(Blah, (a, b, c, a));
fn main() {}
Without using a compiler plugin, no, I don't believe this is possible. Two reasons:
You can't construct identifiers. There's concat_idents!, but due to the way macros are expanded, it's useless in this situation.
You can't do non-literal comparisons. That is, there's no way of the macro working out that it's already seen a once before.
About the closest you could get is to just outright replace all the provided identifiers with a fixed list of identifiers, but that's probably not what you want; in that case, it'd be easier to just specify that you want 4 fields, and generate a fixed-size array [i32; 4].
My paste crate provides a way for you to expand my_macro!(Blah, (a, b, c, a)) into fields x_a, xx_b, xxx_c, xxxx_d if that naming convention would work for you. We prepend an additional x for each field, followed by an underscore, followed by the original field name so that way no fields can end up with conflicting names. This approach works with any Rust version >= 1.31.0.
use paste::paste;
macro_rules! my_macro {
($name:ident, ($($field:ident),*)) => {
my_macro_helper!($name (x) () $($field)*);
};
}
macro_rules! my_macro_helper {
// In the recursive case: append another `x` into our prefix.
($name:ident ($($prefix:tt)*) ($($past:tt)*) $next:ident $($rest:ident)*) => {
my_macro_helper!($name ($($prefix)* x) ($($past)* [$($prefix)* _ $next]) $($rest)*);
};
// When there are no fields remaining.
($name:ident ($($prefix:tt)*) ($([$($field:tt)*])*)) => {
paste! {
// Expands to:
// pub struct Blah {
// x_a: i32,
// xx_b: i32,
// xxx_c: i32,
// xxxx_a: i32,
// }
pub struct $name {
$(
[<$($field)*>]: i32,
)*
}
// Expands to:
// impl Blah {
// pub fn foo(&self) -> i32 {
// 0 + self.x_a + self.xx_b + self.xxx_c + self.xxxx_a
// }
// }
impl $name {
pub fn foo(&self) -> i32 {
0 $(
+ self.[<$($field)*>]
)*
}
}
}
};
}
my_macro!(Blah, (a, b, c, a));

How to use constructs defined in module in exporting macro implicitly

Trying to export a macro from module. Macro generates structure implementing some traits defined in module. Is there a way to get macro without importing that traits manually?
// src/lib.rs
#![crate_name="macro_test"]
#![crate_type="lib"]
#![crate_type="rlib"]
pub trait B<T> where T: Copy {
fn new(x: T) -> Self;
}
#[macro_export]
macro_rules! test {
( $n:ident ) => {
struct $n<T> where T: Copy {
x: T
}
impl<T> B<T> for $n<T> where T: Copy {
fn new(x: T) -> Self {
$n { x: x }
}
}
}
}
// tests/test_simple.rs
#[macro_use]
extern crate macro_test;
test!(Test);
#[test]
fn test_macro() {
let a = Test::<i32>::new(1);
}
In that case I get an error:
<macro_test macros>:2:54: 2:61 error: use of undeclared trait name `B` [E0405]
<macro_test macros>:2 struct $ n < T > where T : Copy { x : T } impl < T > B < T > for $ n < T >
If I rewrite the trait implementation with $crate variable:
impl<T> $crate::B<T> for $n<T> where T: Copy {
error message changes to next:
tests\test_simple.rs:8:13: 8:29 error: no associated item named `new` found for type `Test<i32>` in the current scope
tests\test_simple.rs:8 let a = Test::<i32>::new(1);
^~~~~~~~~~~~~~~~
tests\test_simple.rs:8:13: 8:29 help: items from traits can only be used if the trait is in scope; the following trait is implemented but not in scope, perhaps add a `use` for it:
tests\test_simple.rs:8:13: 8:29 help: candidate #1: use `macro_test::B`
Why does it happen?
Because you can't call trait methods without useing the trait. That's got nothing to do with macros—it's just a standard rule in Rust.
Maybe you want the macro to generate an inherent impl instead? i.e.
impl<T> $n<T> where T: Copy {
pub fn new(x: T) -> Self {
$n { x: x }
}
}
instead of what you have currently.

Using a macro type argument inside a generated function

I'm trying to implement a macro which implements the Add trait for a struct, like so:
macro_rules! implement_add {
($t:ty) => {
impl std::ops::Add for $t {
type Output = $t;
fn add(self, rhs: $t) -> $t {
$t(self.0 + rhs.0) // error on this line
}
}
}
}
pub struct Length(f64);
implement_add!(Length);
fn main() {}
However, this gives an error on the indicated line:
<anon>:6:17: 6:19 error: unexpected token: `Length`
<anon>:6 $t(self.0 + rhs.0) // error on this line
^~
This makes no sense to me. Especially since, if I replace $t there with Length, it compiles fine. Am I doing something wrong in my macro?
Playground: http://is.gd/EIEKub
You've stumbled on a subtle bit of Rust's type system. Length is a type, but Length() is a function. These exist in different namespaces.
One work around is to extend your macro to accept a type and a function:
macro_rules! implement_add {
($t:ty, $c:ident) => {
impl std::ops::Add for $t {
type Output = $t;
fn add(self, rhs: $t) -> $t {
$c(self.0 + rhs.0) // error on this line
}
}
}
}
pub struct Length(f64);
implement_add!(Length, Length);
fn main() {}

What's the standard way to create custom conversion between types in Rust?

If I defined some enum and wanted to create a parser from string to that type, is there something better than just:
impl TheType {
fn from_str(s: &str) -> TheType {
// ...
}
}
The right way for converting from a string / parsing text is to implement the FromStr trait. For the example from the question it would look like this:
use std::str::FromStr;
enum Failure {
ReasonOne,
ReasonTwo,
}
impl FromStr for TheType {
type Err = Failure;
fn from_str(s: &str) -> Result<TheType, Self::Err> {
unimplemented!()
}
}
For generic conversion that cannot fail, you should implement the std::convert::From trait:
use std::convert::From;
#[derive(PartialEq, Eq, Debug)]
enum MyEnum {
One,
Two,
Many(i64),
}
impl From<i64> for MyEnum {
fn from(val: i64) -> Self {
match val {
1 => MyEnum::One,
2 => MyEnum::Two,
_ => MyEnum::Many(val),
}
}
}
fn main() {
assert_eq!(MyEnum::from(1), MyEnum::One);
assert_eq!(MyEnum::from(2), MyEnum::Two);
assert_eq!(MyEnum::from(3), MyEnum::Many(3));
}
Conveniently, implementing From also automatically implements Into:
let one: MyEnum = 1.into(); assert_eq!(one, MyEnum::One);
let two: MyEnum = 2.into(); assert_eq!(two, MyEnum::Two);
let many: MyEnum = 3.into(); assert_eq!(many, MyEnum::Many(3));
For potentially failing conversion, you should implement std::convert::TryFrom instead. It's only available in Rust 1.34 and up though, before these versions you can use the implementation in the conv crate.