Jump to content
  • Advertisement
Sign in to follow this  
Riddle

[.net] Generic numeric class [C# 2.0]

This topic is 5075 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello! Is it possible to make a generic Vector class? a.) Generic static methods are not possible b.) -> no operator overloading c.) No generic properties / indexer -> use generic methods d.) ... Could I make the Vector as a Template with C++/CLI ? Thank you guys! :)

Share this post


Link to post
Share on other sites
Advertisement
It is possible to make a generic Vector Class with out operator overloading, I am not quiet sure what you mean by generic property and Indexer. Why try to re-invent the Vector class again... is it for a learning purpos... to understand vector class??

I am sure there are some other vector class out there, because I have used apvector class in one of my project for my college class.

Good luck with your programming. =)

Share this post


Link to post
Share on other sites
My "old" math- .dll ( C# 2003 ) has a 1.8k lines Vector3 class. The class itself was meant for us in 3D applications using OGL. So I decided to use floats. Now with C# 2.0 my hope raised that I could make a more generic Vector3 class.

I just tried out the VS 2005 C# Beta and found out about the disadvantages of generics.

1.) Most important: Generic static functions are not aviable.


public static Vector3<T> Add( Vector3<T> left, Vector3<T> right )
{
return new Vector3<T>( left.x + right.x, left.y + right.y );
}



2.) No operator overloads! I love operator overloading! v3 = v1 * s; Is clearer than with methods.

3.) Properties:

public Bla<float>
{
get{} set{}
}

Doesn't compile...





Soo... I have to make non generic versions of my Vector classes. Well that's not that hard. Eg:



using T = System.Float;

public struct Vector3
{
T x; T y; T z;
}


// ...................

using T = System.Decimal;

public struct Vector3m
{
T x; T y; T z;
}





Share this post


Link to post
Share on other sites
C# generics does support static methods and operators. Look at this article <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvs05/html/csharp_generics.asp> . Here is the example they give on a static method:


public class MyClass<T>
{
public static T SomeMethod<X>(T t,X x)
{..}
}
int number = MyClass<int>.SomeMethod<string>(3,"AAA");


Here is the example for an operator:


public class LinkedList<K,T>
{
public static LinkedList<K,T> operator+(LinkedList<K,T> lhs,
LinkedList<K,T> rhs)
{
return concatenate(lhs,rhs);
}
static LinkedList<K,T> concatenate(LinkedList<K,T> list1,
LinkedList<K,T> list2)
{
LinkedList<K,T> newList = new LinkedList<K,T>();
Node<K,T> current;
current = list1.m_Head;
while(current != null)
{
newList.AddHead(current.Key,current.Item);
current = current.NextNode;
}
current = list2.m_Head;
while(current != null)
{
newList.AddHead(current.Key,current.Item);
current = current.NextNode;
}
return newList;
}
//Rest of LinkedList
}

Share this post


Link to post
Share on other sites
Hmm, well. That's a list not a math- vector. A list has to use less numeric operations. =3

*thinks*

Thank you! :)








I get an error when I compile any code in C# 2005!


Warning 1 Invalid search path 'C:\Programme\Microsoft Visual Studio .NET\FrameworkSDK\Lib\' specified in 'LIB environment variable' -- 'The system couldn't find the path. '




Where can I change the 'LIB environment variable' ?


That result's into strange other errors. It can't find System.Float, ..
float (the keyword) works fine! :3


Hmm, help please :D

Share this post


Link to post
Share on other sites
To change your LIB environment variable, right-click your "My Computer" icon and select "properties". Then click the "Advanced" tab, and click on the "Environment Variables" button. There you will see a list of environment variables and they're values. You can modify them there. You may have to restart Visual Studio for the change to take effect.

Share this post


Link to post
Share on other sites
Quote:

a.) Generic static methods are not possible

That's not true; C# explicitly supports generic static methods. When invoking the static method, you just need to provide the concrete type at the call site:


public class Carton<T>
{
public static T LookInside(T item)
{
// ...
}
}

// Need to provide concrete types for resolution to a specific type to occur.
int contents1 = Carton<int>.LookInside(5);
string contents2 = Carton<string>.LookInside("What's in here?");
bool contents3 = Carton<bool>.LookInside(false);



HTH,

Share this post


Link to post
Share on other sites
Quote:
Original post by kSquared
Quote:

a.) Generic static methods are not possible

That's not true; C# explicitly supports generic static methods. When invoking the static method, you just need to provide the concrete type at the call site:

*** Source Snippet Removed ***

HTH,



Ahh, THank you two!

Okay, I read that in a tutorial. Ttank you :)



Is Template overloading possible? I mean:

public static T DoSMT<float>( T t ){}
public static T DoSMT<int>( T t ){}

Share this post


Link to post
Share on other sites
Quote:
Is Template overloading possible? I mean:
*** Source Snippet Removed ***

Unfortunately, no. Just to be clear, C# supports generics, not templates. There's a difference between those two. Generics do not allow user-defined specializations.

Also, two quick corrections. First, your examples:

public static T DoSMT<float>( T t ){}
public static T DoSMT<int>( T t ){}

would not compile because you've specified the return type as T, but nothing is returned (compile-time error). Second, you call this "template overloading", but this is actually called "template specialization". I like to be a stickler for that kind of thing. :)

HTH,

Share this post


Link to post
Share on other sites
For my projects I use quite a flexible workaround:

A static class that is a kind of registry for pseudo-specializations:

public static class Arithmetics<T> {
public delegate T Binary(T value1, T value2);
public delegate T Unary(T value);

#region Add
static Binary add;

public static Binary AddHandler {
get { return add; }
set { add = value; }
}

public static T Add(T value1, T value2) {
System.Diagnostics.Debug.Assert( add != null, "No add-handler for " + typeof( T ) + " registered" );
return add( value1, value2 );
}
#endregion


#region Subtract
static Binary subtract;

public static Binary SubtractHandler {
get { return subtract; }
set { subtract = value; }
}

public static T Subtract(T value1, T value2) {
System.Diagnostics.Debug.Assert( subtract != null, "No subtract-handler for " + typeof( T ) + " registered" );
return subtract( value1, value2 );
}
#endregion


#region Invert
static Unary invert;

public static Unary InvertHandler {
get { return invert; }
set { invert = value; }
}

public static T Invert(T value) {
System.Diagnostics.Debug.Assert( invert != null, "No invert-handler for " + typeof( T ) + " registered" );
return invert( value );
}
#endregion
// and so on
}





Similarly, a registry for conversion routines:

static class Conversion<From, To>
{
static Converter<From, To> converter;

public static Converter<From, To> Converter {
get { return converter; }
set { converter = value; }
}

public static To Convert(From value) {
System.Diagnostics.Debug.Assert( converter != null,
"No converter from " + typeof(From) + " to " + typeof(To) + " registered");
return converter( value );
}
}






These can be used by the vertex struct or any other generic type

struct Vector3<T> {
public T X, Y, Z;

public Vector3(T x, T y, T z) {
X = x; Y = y; Z = z;
}

public override string ToString() {
return string.Format( "[{3}] x:{0}, y:{1}, z:{2}",
X.ToString(),
Y.ToString(),
Z.ToString(),
typeof(T).Name );
}


public static Vector3<T> operator +(Vector3<T> a, Vector3<T> b) {
return new Vector3<T>(
Arithmetics<T>.Add( a.X, b.X ),
Arithmetics<T>.Add( a.Y, b.Y ),
Arithmetics<T>.Add( a.Z, b.Z ) );
}

public static Vector3<T> operator -(Vector3<T> a, Vector3<T> b) {
return new Vector3<T>(
Arithmetics<T>.Subtract( a.X, b.X ),
Arithmetics<T>.Subtract( a.Y, b.Y ),
Arithmetics<T>.Subtract( a.Z, b.Z ) );
}

public static Vector3<T> operator -(Vector3<T> a) {
return new Vector3<T>(
Arithmetics<T>.Invert( a.X ),
Arithmetics<T>.Invert( a.Y ),
Arithmetics<T>.Invert( a.Z));
}

// cool! convert to a vector of another type!
public Vector3<U> Convert<U>() {
return new Vector3<U>(
Conversion<T, U>.Convert( X ),
Conversion<T, U>.Convert( Y ),
Conversion<T, U>.Convert( Z ) );
}
}





All I have to do is to register handlers that perform the (specialized) operations:

static void Main() {
// register arithmetic and conversion-handlers
Arithmetics<float>.AddHandler = delegate(float a, float b) { return a + b; };
Arithmetics<float>.SubtractHandler = delegate(float a, float b) { return a - b; };
Arithmetics<float>.InvertHandler = delegate(float a) { return -a; };
Conversion<float, double>.Converter = delegate(float value) { return value; };

// now we are ready to use the vector
Vector3<float> fv1 = new Vector3<float>( 1, 2, 3 );
Vector3<float> fv2 = new Vector3<float>( 2, 3, 4 );
Vector3<float> result = fv1 + fv2;
Vector3<double> converted = result.Convert<double>();

Console.WriteLine( fv1 );
Console.WriteLine( fv2 );
Console.WriteLine( result );
Console.WriteLine( converted );

Console.ReadKey();
}





I've seen other solutions that involved some kind of primitive-wrapper-structs implementing a IArithmetic<T> kind of interface. However, I find my solution to be much cleaner and easier to extend.

Pros:
A quite clean solution that does not need a huge amount of extra wrapper-classes. It can be extended quite simply by adding new handler. Handlers can even be exchanged at runtime for whatever reason.

Cons:
There's a performance penalty when calling delegates, so be sure to benchmark different solution. Neither is this implementation thread- or crossdomain-safe. Well, it's just the way I do it. Another drawback is that the presence of a required handler is only checked at runtime (here I use assertions).

Regards,
Andre


P.S.: [rant]I tried to port this to Java. However, there it seems generics are supported on instances only. One more reason why I like C# better than Java[/rant]
P.P.S.: This technique can be extended to be used for generic double dispatching, e.g. for bounding-volume intersection or scenegraphs. For those of you capable of German I wrote this down in an article

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!