Jump to page: 1 2
Thread overview
Beginner problem: casting in opCmp override
Jul 08, 2013
Ugbar Ikenaki
Jul 08, 2013
Jonathan M Davis
Jul 08, 2013
Ugbar Ikenaki
Jul 08, 2013
Ugbar Ikenaki
Jul 08, 2013
Jonathan M Davis
Jul 08, 2013
H. S. Teoh
Jul 08, 2013
Ali Çehreli
Jul 08, 2013
Ugbar Ikenaki
Jul 08, 2013
Ugbar Ikenaki
Jul 08, 2013
Ugbar Ikenaki
Jul 08, 2013
Jonathan M Davis
Jul 08, 2013
H. S. Teoh
Jul 08, 2013
Jonathan M Davis
Jul 08, 2013
H. S. Teoh
Jul 08, 2013
Jonathan M Davis
Jul 09, 2013
Jonathan M Davis
Jul 09, 2013
H. S. Teoh
July 08, 2013
I'm trying to implement rational numbers with fully functioning comparison operators, but I can't seem to figure out why I'm getting this error and any help would be appreciated:

Error: cannot cast from object.Object to Rat

The code I have is as follows:

int opCmp( Object o ) {
	Rat other = cast(Rat) o; <--- this line throws the error
        …
        //stuff to return -1, 0, or 1 to opCmp with rational numbers for <, >=, etc.
        …
}

Thanks to anyone who can help!
July 08, 2013
On Monday, July 08, 2013 23:21:59 Ugbar Ikenaki wrote:
> I'm trying to implement rational numbers with fully functioning comparison operators, but I can't seem to figure out why I'm getting this error and any help would be appreciated:
> 
> Error: cannot cast from object.Object to Rat
> 
> The code I have is as follows:
> 
> int opCmp( Object o ) {
> 	Rat other = cast(Rat) o; <--- this line throws the error
> >          //stuff to return -1, 0, or 1 to opCmp with rational
> numbers for <, >=, etc.
> > }
> 
> Thanks to anyone who can help!

You're going to need to provide more code than that. Without knowing anything about Rat, we can't help you.

On a side note, I point out that talking about compiler errors as being "thrown" is going to cause confusion, as throwing is something completely different.

- Jonathan M Davis
July 08, 2013
Also…Rat is a struct, not a class. Herein might lie the problem.
July 08, 2013
Thanks for the quick response!

Here is the initialization code for my Rat struct. I created a GCD function that I've tested to work fine:

import std.stdio, std.exception;

struct Rat {
	private long n; //Numerator
	private long d; //Denominator
	
	
	
	public this( long numerator, long denominator ) {
		enforce( denominator != 0, "Error. Denominator can not be 0. (Rat.this)");
		
		//Default 0-value Rat object
		if( numerator == 0 || numerator == -0 ) {
			n = 0;
			d = 1;
			
		} else {
			//Assign appropriates signs (+ / -) to numerator
			// -x/-y
			if( numerator < 0 && denominator < 0 ) {
				numerator = -numerator;
				denominator = -denominator;
			// x/-y
			} else if( numerator > 0 && denominator < 0 ) {
				numerator = -numerator;
				denominator = -denominator;
			}
			
			//Find GCD of numerator and denominator
			long gcd = gcd( numerator, denominator );
			
			//Return reduced fraction of numerator and denominator (invariant)
			n = numerator / gcd;
			d = denominator / gcd;
		}
	}



The following is the code to override the opCmp function:


	int opCmp( Object o ) {
		Rat other = cast(Rat) o;
		
		long num1 = n;
		long den1 = d;
		long num2 = other.n;
		long den2 = other.d;
		
		//If denominators are not equal to each other...
		if( den1 != den2 ) {
			//Set denominators equal to each other (with corresponding numerators)
			num1 *= den2;
			den1 *= den2;

			if(den2 < den1) {
				num2 *= (den1 / den2);
				den2 *= (den1 / den2);
			} else {
				num2 *= (den2 / den1);
				den2 *= (den2 / den1);
			}
			
			//Return opCmp int value (-1, 0, 1)
			if( num1 - num2 < 0 ) {
				return -1;
			} else if( num1 - num2 == 0 ) {
				return 0;
			} else {      //if( num1 - num2 > 0 )
				return 1;
			}
			
		//If denominators are equal to each other...
		} else {
			//Less than
			if( num1 - num2 < 0 ) {
				return -1;
                        //Equal to
			} else if( num1 - num2 == 0 ) {
				return 0;
                        //Greater than
			} else {      //if( num1 - num2 > 0 )
				return 1;
			}
		}
	}
July 08, 2013
On Monday, July 08, 2013 23:31:14 Ugbar Ikenaki wrote:
> Also…Rat is a struct, not a class. Herein might lie the problem.

So, this is Rat's opCmp, correct? If it's a struct, it makes no sense for it to take an Object. Object is the base class for all classes and has nothing to do with structs. opCmp needs to take Rat, not Object. And to be fully functional, you might need to have a ref overload as well (since sometimes the compiler and runtime get overly picky about exact signatures - which is slowly getting fixed fortunately). So, something like this should work:

int opCmp(Rat other)
{
    return this.opCmp(other);
}

int opCmp(ref Rat other)
{
    //do stuff for comparison
}

- Jonathan M Davis
July 08, 2013
On 07/08/2013 02:21 PM, Ugbar Ikenaki wrote:
> I'm trying to implement rational numbers with fully functioning
> comparison operators, but I can't seem to figure out why I'm getting
> this error and any help would be appreciated:
>
> Error: cannot cast from object.Object to Rat
>
> The code I have is as follows:
>
> int opCmp( Object o ) {
>      Rat other = cast(Rat) o; <--- this line throws the error
> >          //stuff to return -1, 0, or 1 to opCmp with rational numbers
> for <, >=, etc.
> > }
>
> Thanks to anyone who can help!

Yeah, the signature of opCmp is different for structs so you don't need to cast.

Once you have the subtraction defined, opCmp can be as simple as the following:

    /* Sort order operator: Returns a negative value if this
     * fraction is before, a positive value if this fraction
     * is after, and zero if both fractions have the same sort
     * order. */
    int opCmp(const ref Fraction rhs) const
    {
        immutable result = this - rhs;
        /* Being a long, num cannot be converted to int
         * automatically; it must be converted explicitly by
         * 'to' (or cast). */
        return to!int(result.num);
    }

I have a couple of chapters that go over operator overloading.

Operator Overloading:

  http://ddili.org/ders/d.en/operator_overloading.html

Object is specifically for classes:

  http://ddili.org/ders/d.en/object.html

Ali

July 08, 2013
On Mon, Jul 08, 2013 at 02:42:30PM -0700, Jonathan M Davis wrote:
> On Monday, July 08, 2013 23:31:14 Ugbar Ikenaki wrote:
> > Also…Rat is a struct, not a class. Herein might lie the problem.
> 
> So, this is Rat's opCmp, correct? If it's a struct, it makes no sense for it to take an Object. Object is the base class for all classes and has nothing to do with structs. opCmp needs to take Rat, not Object. And to be fully functional, you might need to have a ref overload as well (since sometimes the compiler and runtime get overly picky about exact signatures - which is slowly getting fixed fortunately). So, something like this should work:
> 
> int opCmp(Rat other)
> {
>     return this.opCmp(other);
> }
> 
> int opCmp(ref Rat other)
[...]

The second overload above should be:

	int opCmp(ref const Rat other) const

otherwise the typeinfo of Rat will be wrong, and using Rat in AA's will not work correctly. (DMD is very picky about the exact signature of opCmp when it's generating typeinfos -- as I found out yesterday.)


T

-- 
I think the conspiracy theorists are out to get us...
July 08, 2013
Wow! You guys are fast and helpful! Thank you Jonathan and Ali! I already got it to work, and Ali, your book is great! I've read about the first 150 pages. I'll check out those operator overloading chapters for sure.

-U
July 08, 2013
And thanks for that pointer, too, H.S.
July 08, 2013
Here's one more question:

Before I knew that opEquals existed, I tried overloading the equality expressions (== and !=) in opBinary using the code below. It worked. Why would the overloaded opBinary version get called if the equality expressions are held in opEquals? I'm just interested in knowing how dmd chooses where to take an expression from if it lies in multiple places (e.g. == in opEquals and opBinary), even if what I did was just add the == operator to opBinary. (Is that what I did there?)

       override bool opBinary( string op ) ( Rect r ) if( op == "==" ) {
		//Check if rectangle coordinates are equal
		if( left == r.left && right == r.right && top == r.top && bottom == r.bottom ) {
			return true;
		} else {
			return false;
		}
	}


Thanks!
« First   ‹ Prev
1 2