How can an operator be overloaded for different RHS types and return values? - operator-overloading

Given the following struct:
struct Vector3D {
x: f32,
y: f32,
z: f32
}
I want to overload its * operator to do a dot product when the right hand side is a Vector3D, and to do an element-wise multiplication when the RHS is a f32. My code looks like this:
// Multiplication with scalar
impl Mul<f32, Vector3D> for Vector3D {
fn mul(&self, f: &f32) -> Vector3D {
Vector3D {x: self.x * *f, y: self.y * *f, z: self.z * *f}
}
}
// Multiplication with vector, aka dot product
impl Mul<Vector3D, f32> for Vector3D {
fn mul(&self, other: &Vector3D) -> f32 {
self.x * other.x + self.y * other.y + self.z * other.z
}
}
The compiler says for the first impl block:
Vector3D.rs:40:1: 44:2 error: conflicting implementations for trait `std::ops::Mul`
Vector3D.rs:40 impl Mul<f32, Vector3D> for Vector3D {
...
Vector3D.rs:53:1: 57:2 note: note conflicting implementation here
Vector3D.rs:53 impl Mul<Vector3D, f32> for Vector3D {
...
and vice versa for the other implementation.

As of Rust 1.0, you can now implement this:
use std::ops::Mul;
#[derive(Copy, Clone, PartialEq, Debug)]
struct Vector3D {
x: f32,
y: f32,
z: f32,
}
// Multiplication with scalar
impl Mul<f32> for Vector3D {
type Output = Vector3D;
fn mul(self, f: f32) -> Vector3D {
Vector3D {
x: self.x * f,
y: self.y * f,
z: self.z * f,
}
}
}
// Multiplication with vector, aka dot product
impl Mul<Vector3D> for Vector3D {
type Output = f32;
fn mul(self, other: Vector3D) -> f32 {
self.x * other.x + self.y * other.y + self.z * other.z
}
}
fn main() {
let a = Vector3D {
x: 1.0,
y: 2.0,
z: 3.0,
};
let b = a * -1.0;
let c = a * b;
println!("{:?}", a);
println!("{:?}", b);
println!("{:?}", c);
}
The big change that allows this is the introduction of associated types, which shows up as the type Output = bit in each implementation. Another notable change is that the operator traits now take arguments by value, consuming them, so I went ahead and implemented Copy for the struct.

At the moment only a single impl is allowed per trait-type pair.
This situation will be improved with RFC 48, but it's not the full story (it's not really any of the story). The relevant section is Coherence, and it certainly doesn't mention the operator overloading case specifically, and essentially says it is still illegal:
The following example is NOT OK:
trait Iterator<E> { ... }
impl Iterator<char> for ~str { ... }
impl Iterator<u8> for ~str { ... }
Niko Matsakis (author of that RFC & Rust-type-system expert) has been thinking about these overloading traits specifically: he is the one who published ("What if I want overloading?") the trick below, but he has expressed his distaste towards it, mentioning that he'd like to allow implementations as you have written...
... which is where his RFC 135 comes in. The situation is described in detail in "multidispatch traits".
You can work-around it for now using secondary traits. The extra layer of traits allows you to write just one impl Mul<...> for Vector3D but comes at the cost of requiring a new trait for each type for which you wish to have multiple implementations of Mul.
#[deriving(Show)]
struct Vector3D {
x: f32,
y: f32,
z: f32
}
trait MulVec3D<Res> {
fn do_mul(&self, v: &Vector3D) -> Res;
}
// Multiplication with scalar
impl MulVec3D<Vector3D> for f32 {
fn do_mul(&self, v: &Vector3D) -> Vector3D {
Vector3D {x: v.x * *self, y: v.y * *self, z: v.z * *self}
}
}
// Multiplication with vector, aka dot product
impl MulVec3D<f32> for Vector3D {
fn do_mul(&self, v: &Vector3D) -> f32 {
self.x * v.x + self.y * v.y + self.z * v.z
}
}
impl<Res, RHS: MulVec3D<Res>> Mul<RHS, Res> for Vector3D {
fn mul(&self, rhs: &RHS) -> Res {
rhs.do_mul(self)
}
}
fn main() {
let a = Vector3D { x: 1.0, y: 2.0, z: 3.0 };
let b = Vector3D { x: -3.0, y: 2.0, z: -1.0 };
println!("{}, {}", a * 2f32, a * b); // Vector3D { x: 2, y: 4, z: 6 }, -2
}

Related

Generic with default value of nil

I'm attempting to create a generic class/struct initializer that converts any value it takes in and assigns it to its Double properties. (Note: the as! or as? pattern below is just being used to save space here. I'm actually using this extension to convert my values.)
The idea here is that I'd like to be able to mix Integers, Doubles, CGFloats, etc (i.e. anything in the Numeric generic type constraint) and have them all end up as Doubles. It works in other situations, but I'm running into an issue here.
In the pared down example below I'm creating a Vector class and the z property should be able to be nil in case we're only dealing with 2 dimensions.
struct Vector {
var x: Double
var y: Double
var z: Double?
public init<X: Numeric, Y: Numeric, Z: Numeric>(_ x: X, _ y: Y, _ z: Z? = nil){
self.x = x as! Double
self.y = y as! Double
self.z = z as? Double
}
}
var myVector = Vector(4, 3.4)
print("""
\(myVector.x)
\(myVector.y)
\(myVector.z)
"""
)
The problem is that I get an error that says Generic parameter 'Z' could not be inferred.
I would do this with two separate intitializers, one of which doesn't need to have an unused generic Z:
struct Vector {
var x: Double
var y: Double
var z: Double?
}
extension Vector {
public init<X: Numeric, Y: Numeric>(_ x: X, _ y: Y) {
self.init(x: x as! Double, y: y as! Double, z: nil as Double?)
}
public init<X: Numeric, Y: Numeric, Z: Numeric>(_ x: X, _ y: Y, _ z: Z? = nil) {
self.init(x: x as! Double, y: y as! Double, z: z as? Double)
}
}

Apply void function on array

I am learning swift right now and wanted to write a quicksort algorithm for [Int]
func swap(array:[Int], x:Int, y:Int)->[Int] { //swap elements in array
var result:[Int] = array
result[y] = array[x]
result[x] = array[y]
return result
}
func split(array:[Int], u:Int, o:Int , p:Int)->Int { //where the sorting happens
let pivot:Int = array[p]
swap(array: array, x: p, y: o)
var pn:Int = u
for j in u...o {
if(array[j] <= pivot) {
swap(array: array, x: pn, y: j)
pn = pn+1
}
}
swap(array: array, x: pn, y: o);
return pn;
}
func quickSortR(array:[Int],u:Int ,o:Int) { //recursive call
if(u < o){
let p:Int = o
let pn:Int = split(array: array, u: u, o: o, p: p)
quickSortR(array: array,u: u,o: pn-1)
quickSortR(array: array,u: pn+1,o: o)
}
}
func quickSort(array:[Int]) { //initial call
quickSortR(array: array, u: 0, o: array.count-1)
}
My problem is that I don't know how to apply this implementation on an array.
For example if I got the array a:[Int] = [3,1,2].
I can't check if the implementation is working by print(quickSort(a)), because the return type of quickSort is void.
Of course I can't apply quickSort on that array like a.quickSort(a)
I really don't want to change my implementation of the algorithm by much if it isn't the cause of that problem (e.g. just the signature or return type)
Just improve your syntax:
func swap(array: inout [Int], x:Int, y:Int) { //swap elements in array
let temp = array[x]
array[x] = array[y]
array[y] = temp
}
func split(array: inout [Int], u:Int, o:Int , p:Int) -> Int { //where the sorting happens
print(ar, u , o , p)
let pivot:Int = array[p]
swap(array: &array, x: p, y: o)
var pn:Int = u
for j in u..<o {
if(array[j] <= pivot) {
swap(array: &array, x: pn, y: j)
pn = pn+1
}
}
swap(array: &array, x: pn, y: o);
return pn;
}
func quickSortR(array: inout [Int],u:Int ,o:Int) { //recursive call
if(u < o){
let p:Int = o
let pn:Int = split(array: &array, u: u, o: o, p: p)
quickSortR(array: &array,u: u,o: pn-1)
quickSortR(array: &array,u: pn+1,o: o)
}
}
func quickSort(array: inout [Int]) { //initial call
quickSortR(array: &array, u: 0, o: array.count-1)
}
If you use func swap(array: [Int]) array is immutable inside the method. It just copies. Using inout resolves this problem.
To check the code use somethink like this:
var ar = [1]
quickSort(array: &ar)
print(ar)

Swift closure compiling failed with expression too complex

public static func easeOutQuint(_ t: Float, _ b: Float, _ c: Float, _ d: Float = 1.0) -> Float {
return {
return c * ($0 * $0 * $0 * $0 * $0 + 1.0) + b
}(t / d - 1.0)
}
I'm not familiar with closure, so I can not fix it by myself, can someone help me?
Closures are a great tool but, in this particular example, you would be better off without them IMO...
For instance, you could rewrite your function simply as:
public static func easeOutQuint(_ t: Float, _ b: Float, _ c: Float, _ d: Float = 1.0) -> Float {
let x = (t / d - 1.0)
return c * (pow(x, 5) + 1) + b
}
And, by the way, this should compile just fine in any Swift compiler you come across ;)

How to compare generic objects in Swift?

consider the following simplified snippet:
class Foo<T: Equatable> {
var x: T
init(_ x: T, _ y: T) {
self.x = x
if (x == y) {
// do something
}
}
}
I would like this class to work for all kinds of Ts that are somehow comparable. Ideally it would compare the identities if T is an object and directly compare everything else that conforms to Equatable.
The code above doesn't work for Array for example. If I change Equatable to AnyObject and == to === then it doesn't work for Ints. How do I solve this problem? I thought about creating my own protocol but then I couldn't figure out how to implement it for all types that conform to Equatable.
Edit:
I didn't know that it would work on the Mac because I am on Linux and when I try to compile
Foo<[Int]>([1, 2], [1, 2])
I get the following error:
error: type '[Int]' does not conform to protocol 'Equatable'
Foo<[Int]>([1, 2], [1, 2])
^
A simple solution would be to simply add another initializer for arrays of Equatable elements.
class Foo<T: Equatable> {
init(_ x: T, _ y: T) {
if (x == y) {
print("Initialization by equal equatable types.")
}
}
init(_ x: [T], _ y: [T]) {
if (x == y) {
print("Initialization by equal arrays of equatable types.")
}
}
}
let a = Foo<Int>(1, 1)
/* Initialization by equal equatable types. */
let b = Foo<Int>([1, 2, 3], [1, 2, 3])
/* Initialization by equal arrays of equatable types. */
Depending on what you intend to do with Foo, it may not be necessary to make it a generic class but rather just have generic initializers:
class Foo
{
init<T:Equatable>(_ x: T, _ y: T)
{
if (x == y)
{
// do something
}
}
init<T:AnyObject>(_ x: T, _ y: T)
{
if (x === y)
{
// do something
}
}
}
// in Playground ...
class Bar { }
let C = Foo(3,4) // no error
let O1 = Bar()
let O2 = Bar()
let D = Foo(O1,O2) // no error

define default named arguments in terms of other arguments in scala

I have a case class that stores three tied parameters. I'd like to define companion object that may build the class from any two parameters, something that looks like the sample below, that is obviously incorrect:
def test(start : Float = end - duration, duration : Float = end - start, end : Float = start + duration) {
require( abs(start + duration - end) < epsilon )
...
}
val t1 = test(start = 0f, duration = 5f)
val t2 = test(end = 4f, duration = 3f)
val t3 = test(start = 3f, end = 5f)
What tricks I may use to get similar usage syntax?
You can use type-classes:
// Represents no argument
object NoArg
// Resolves start, duration, stop
trait DurationRes[A,B,C] {
def resolve(s: A, d: B, e: C): (Float, Float, Float)
}
object DurationRes {
implicit object startEndRes extends DurationRes[Float, NoArg.type, Float] {
def resolve(s: Float, d: NoArg.type, e: Float) = (s, e-s, e)
}
implicit object startDurRes extends DurationRes[Float, Float, NoArg.type] {
def resolve(s: Float, d: Float, e: NoArg.type) = (s, d, s+d)
}
// etc.
}
def test[A,B,C](start: A = NoArg, dur: B = NoArg, end: C = NoArg)
(implicit res: DurationRes[A,B,C]) {
val (s,d,e) = res.resolve(start, dur, end)
// s is start, d duration, e end
}
test(start = 1f, end = 2f)
This way it is even type-safe and you cannot call something like:
test(start = 1f)
or even
test()
After a little thinking I've come with another solution (I don't claim it's better, just would like to know if it's even acceptable approach). The essence is to define a class:
class Klass(val x: Int, val y: Int, val z: Int)
and a companion object:
object Klass {
def apply(x: Int, y: Int)(z: Int = x + y) = {
new Klass(x, y, z)
}
// and so on
}
So you can then do val k = Klass(x = 5, y = 6)() and get val k to refer to Klass(5, 6, 11) instance.
And because of small code amount one can probably define a macros to do the job, but that's a little difficult for me as for now, but is an interesting exercise though.
Update
After some time, I'd like to note to you that there are only three combinations of parameters in your case, so wouldn't it be just easier to provide 3 apply() methods by hand? apply(s, d), apply(s, e), apply(d, e) should suffice your needs. And that will save you some typing, because with other approaches you basically have to code all that cases, too.