Skip to main content
gamedev.net
🔒 Locked

[.net] Problem with generics

Started by Numsgil Dec 28, 2006 at 6:09 AM 10 replies 3.6k views
Original Post
Numsgil
Numsgil
I'm porting some C++ code to C# for practice and so I can take advantage of some of the .Net functionality. This is a class I've converted from C++ to almost compiling C#:

class Triplet<scalar>
    {
        public scalar a, b, c;
        public Triplet(scalar A, scalar B, scalar C)
        {
            a = A; b = B; c = C;
        }

        public Triplet()
        {

        }

        public static Triplet<scalar> operator +(Triplet<scalar> A, Triplet<scalar> B)
        {
            return new Triplet<scalar>(A.a + B.a, A.b + B.b, A.c + B.c);
        }

        public static Triplet<scalar> operator /(Triplet<scalar> A, scalar divisor)
        {
            return new Triplet<scalar>(A.a / divisor, A.b / divisor, A.c / divisor);
        }

        public Triplet<scalar> Set(scalar A, scalar B, scalar C)
        {
            a = A; b = B; c = C;
            return this;
        }

        /// <summary>
        /// Returns true if there is a combination of the two triangles points that 
        /// causes them to be equal.  For instance, Triangle 5 0 3 and 3 5 0 would be considered
        /// equal.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if(obj.GetType() != typeof(Triplet<scalar>))
                return false;

            Triplet<scalar> temp = new Triplet<scalar>();
            Triplet<scalar> other = (Triplet<scalar>) obj;

            if(ExactEqual(this, temp.Set(other.a, other.b, other.c)))
                return true;

            if(ExactEqual(this, temp.Set(other.b, other.a, other.c)))
                return true;
            
            if(ExactEqual(this, temp.Set(other.a, other.c, other.b)))
                return true;

            if(ExactEqual(this, temp.Set(other.c, other.b, other.a)))
                return true;

            if(ExactEqual(this, temp.Set(other.b, other.c, other.a)))
                return true;

            if(ExactEqual(this, temp.Set(other.c, other.a, other.b)))
                return true;
            
            return false; 
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public static bool operator ==(Triplet<scalar> A, Triplet<scalar> B)
        {
            return Equals(A, B);
        }

        public static bool operator !=(Triplet<scalar> A, Triplet<scalar> B)
        {
            return !Equals(A, B);
        }

        bool ExactEqual(Triplet<scalar> a, Triplet<scalar> b)
        {
            if(a.a == b.a &&
               a.b == b.b &&
               a.c == b.c)
               return true;
            return false;
        }
    }


I get these compile errors:
Quote:
C:\Succession\source\Workspaces\Succession\SimulationData\GeodesicMesh.cs(22,40): error CS0019: Operator '+' cannot be applied to operands of type 'scalar' and 'scalar' C:\Succession\source\Workspaces\Succession\SimulationData\GeodesicMesh.cs(22,51): error CS0019: Operator '+' cannot be applied to operands of type 'scalar' and 'scalar' C:\Succession\source\Workspaces\Succession\SimulationData\GeodesicMesh.cs(22,62): error CS0019: Operator '+' cannot be applied to operands of type 'scalar' and 'scalar' C:\Succession\source\Workspaces\Succession\SimulationData\GeodesicMesh.cs(27,40): error CS0019: Operator '/' cannot be applied to operands of type 'scalar' and 'scalar' C:\Succession\source\Workspaces\Succession\SimulationData\GeodesicMesh.cs(27,55): error CS0019: Operator '/' cannot be applied to operands of type 'scalar' and 'scalar' C:\Succession\source\Workspaces\Succession\SimulationData\GeodesicMesh.cs(27,70): error CS0019: Operator '/' cannot be applied to operands of type 'scalar' and 'scalar' C:\Succession\source\Workspaces\Succession\SimulationData\GeodesicMesh.cs(89,16): error CS0019: Operator '==' cannot be applied to operands of type 'scalar' and 'scalar' C:\Succession\source\Workspaces\Succession\SimulationData\GeodesicMesh.cs(90,16): error CS0019: Operator '==' cannot be applied to operands of type 'scalar' and 'scalar' C:\Succession\source\Workspaces\Succession\SimulationData\GeodesicMesh.cs(91,16): error CS0019: Operator '==' cannot be applied to operands of type 'scalar' and 'scalar'
By the looks of it, it doesn't like me trying to use my scalar like a number. From what I read in the MSDN, I don't think there's a way around this directly. Does anyone have an idea of how I could accomplish what I'm after?
[size=2]Darwinbots - [size=2]Artificial life simulation
ernow
ernow
The problem is that scalar has no restrictions. In your generic it is possible to use a Triplet and thus /, * etc. would mean nothing.

So you should restrict the type of the scalar using the where option in the declaration of the Generic.

Cheers
joelmartinez
joelmartinez
unfortunately, there's no type parameter constraint that would let you use operators like + and * :-(

You'll have to do something like this:
http://www.codeproject.com/csharp/genericnumerics.asp

And by the time you go through all that, you may as well go back to just making one version of your class/algorithm for floats, and just copy/pasting/replacing for other types if you need them.
Joel Martinez
http://codecube.net
[twitter]joelmartinez[/twitter]
Numsgil
Numsgil
Thanks, I was afraid there'd be no (easy) way. Guess I was right ;)

This really seems a silly language restriction. The suggestion in the link you posted, the IArithmetic, would make perfect sense. That microsoft hasn't implemented it yet is sad.

Guess a line by line conversion isn't going to work ;)
[size=2]Darwinbots - [size=2]Artificial life simulation
John H
John H
ernow touched on something that I think you guys may have missed. It seems this problem has received attention for .NET 3.0, the result being the where clause. Details of its use can be found here.

Hope that helps.
Numsgil
Numsgil
"where" would work if there was a numeric interface. But there's not, and that's the problem. If you read the link joel posted, it'll explain it better than I could.

;)
[size=2]Darwinbots - [size=2]Artificial life simulation
joelmartinez
joelmartinez
Type constraints have been around since .net 2.0 when generics were introduced ... we have the following: struct, class, new(), , and

I see no reason why they couldn't just build it into the CLR ... I mean, all types can implement those operators. Something like this would be awesome
public struct Vector<T> where T : +,-,*,/{     public T x,y,z;     public void Normalize()     {         T len = this.Length;         x /= len;         y /= len;         z /= len;     }....}
Edit: Man, just the mere thought of what additional type constraints could bring to the table is mind blowing. While we're at it, they should add a type constraint for cast operators as well ... that way, if someone develops a generic math library (and they would), some algorithms could specifically cast to double in certain parts to ensure accuracy.
Joel Martinez
http://codecube.net
[twitter]joelmartinez[/twitter]
Numsgil
Numsgil
Can't wait till 5 or 6 years down the road when Microsoft irons out all the kinks. There are definately some nice features about coding in C# compared with C++, but as it stands now C# isn't a direct replacement, for reasons like this.
[size=2]Darwinbots - [size=2]Artificial life simulation
vermilion_wizard
vermilion_wizard
The 'where' clause wouldn't even work if there were numeric interfaces, because the operators +, -, etc. which can be defined can only be defined as static functions, which aren't allowed in interfaces.
joelmartinez
joelmartinez
well, the "numeric interfaces" would simply have to have instance methods like ".Add", and ".Multiply" ... then all of the numeric types like int and float would have to implement those interfaces.
Joel Martinez
http://codecube.net
[twitter]joelmartinez[/twitter]
Foxedup
Foxedup
I might be a bit late for this thread, but cant you use operator overloading on your scalar class?
smitty1276
smitty1276
No, because the scalar class could be System.String, or System.Data.SqlClient.SqlConnection. scalar is a generic type.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.