Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting my Class to Int64, Double etc

Related question: Accessing a Class property without using dot operator

I've created a class called MyDouble looks like this

class MyDouble
{
  double value;
  //overloaded operators and methods
}

I am able to do all kinds of operations on MyDouble. Examples:

MyDouble a = 5.0;
a += 3.0;
...etc

However, this still throws an error

MyDouble a = 5.0;
long b = (Int64)a;  //error
long b = (int64)a.value; //works

How can I define it such that an operation like (Int64)a automatically converts to (Int64)a.value ? I don't want the user to ever have to worry about the existence of the value property.

like image 825
xbonez Avatar asked Feb 29 '12 07:02

xbonez


3 Answers

In order for this conversion to work, you would need an explicit conversion to Int64.

This would look like:

class MyDouble
{
    double value;

    public static explicit operator Int64(MyDouble value)
    {
         return (Int64)value.value;
    }
}
like image 192
Reed Copsey Avatar answered Oct 13 '22 23:10

Reed Copsey


There's an explicit conversion from double to Int64, but not from your class to Int64. all you need to do is define one. Or, if you have a conversion from your class to double, which I suppose you do, you could do this:

long x = (long)(double)a;

However, that's cumbersome; I'd define the explicit conversion operator.

The conversion should be explicit, not implicit, unless you have a good reason for making it explicit.

The language-defined conversion from double to long is explicit because the conversion could cause information loss. You can lose information with this conversion because there are some doubles, like 0.5, that do not convert exactly to long. This is called a narrowing conversion.

With language-defined conversions, narrowing conversions are explicit. If they were implicit, programmers could accidentally lose information by assigning a value of one type to a variable of another type. Defining this conversion as implicit violates that entirely sensible principle, so there would have to be some compelling case for doing so.

Here's an example showing the value of this principle. If narrowing conversions were implicit, it would make code more brittle. Assume that double-to-int conversion is implicit:

class Family
{
    ICollection<Person> Children { get; set; }
}

int GetAverageNumberOfChildren(IEnumerable<Family> families)
{
    return families.Sum(f => f.Children.Count) / families.Count();
}

void SomeMethod(IEnumerable<Family> families)
{
    int averageNumberOfChildren = GetAverageNumberOfChildren(families);
    //...
}

Oops! We have a bug! GetAverageNumberOfChildren should return a double! Let's fix it!

double GetAverageNumberOfChildren(IEnumerable<Family> families)
{
    return families.Average(f => f.Children.Count);
}

Whew, everything compiles and runs! Sure glad we caught that bug!

But, sadly, no. We still have a bug! SomeMethod implicitly converts the double to an int, so where the expected value might be 2.4, the actual value is 2.

Because double-to-int conversion is explicit, the compiler saves us from ourselves. After we fix GetAverageNumberOfChildren, the erroneous program does not compile.

Now, if your MyDouble class had some validation that restricted it to integer values with a range equal to or smaller than the range of long, then you would be safe to make the conversion implicit. But in that case, of course, you should be using long, not double.

like image 1
phoog Avatar answered Oct 13 '22 23:10

phoog


An implicit conversion will work as well as an explicit conversion.

public static implicit operator long(MyDouble m)
{
    return (long) m.value;
}

With this in place you can do:

long b = (Int64) a;

or just

long b = a;

This is just to illustrate that the conversion need not be explicit. As noted, however, it should be explicit because of the potential for data loss.

like image 1
Jay Avatar answered Oct 13 '22 23:10

Jay