Generics limitation...

G

Guest

I try to compare to values of generic value type T in a generic class as
follow:

public class C<T> where T : struct
{
private T value1;
private T value2;

C(T value1, T value2)
{
this.value1 = value1;
this.value2 = value2;
}

public void SomeMethod()
{
if (value1 != value2)
DoSomething();
}
}

and I got the following message at compile time :

"Operator '!=' cannot be applied to operands of type 'T' and 'T'"

Ok, I can use the following code :

if (value1.Equals(value2) == false)
DoSomething();

but doing so, I'm loosing all the advantage of generics
==> value1 and value2 are boxed before comparison occurs...

It was already the case for variable initialisation, I need to cast a value
to Object before it can be cast back to T (see : 12/29/2005 post "Generics
limitation on .Net") :

value1 = (T)(Object)Int32.MinValue;

since it was used once in my class, I didn't care about extra
boxing/unboxing operation.

But value1 vs value2 comparison occurs in a loop in real situation (I mean
in my real program) :

for (Int32 i = value1.Length; i-- != 0; i++)
{
if (value1 != value2)
DoSomething();
}

The question is : Does generics really usefull in such sitautions ?
 
G

Guest

I try to compare to values of generic value type T in a generic class as

You should read:

I try to compare two values of generic value type T in a generic class as
follow:

;-)


Luc Vaillant said:
I try to compare to values of generic value type T in a generic class as
follow:

public class C<T> where T : struct
{
private T value1;
private T value2;

C(T value1, T value2)
{
this.value1 = value1;
this.value2 = value2;
}

public void SomeMethod()
{
if (value1 != value2)
DoSomething();
}
}

and I got the following message at compile time :

"Operator '!=' cannot be applied to operands of type 'T' and 'T'"

Ok, I can use the following code :

if (value1.Equals(value2) == false)
DoSomething();

but doing so, I'm loosing all the advantage of generics
==> value1 and value2 are boxed before comparison occurs...

It was already the case for variable initialisation, I need to cast a value
to Object before it can be cast back to T (see : 12/29/2005 post "Generics
limitation on .Net") :

value1 = (T)(Object)Int32.MinValue;

since it was used once in my class, I didn't care about extra
boxing/unboxing operation.

But value1 vs value2 comparison occurs in a loop in real situation (I mean
in my real program) :

for (Int32 i = value1.Length; i-- != 0; i++)
{
if (value1 != value2)
DoSomething();
}

The question is : Does generics really usefull in such sitautions ?
 
N

Nicholas Paldino [.NET/C# MVP]

Luc,

How are you losing the advantage of generics? Generics doesn't lift the
type operators from the type. In other words, if you overload the ==
operator (or != operator in this case), that is NOT visible to your generic
class.

In order to get around it, you will have to create an interface which
exposes the operations, and performs them (instead of using == or !=).
Either that, or you assign a type to the class internally that will handle
the operations based on the type.
 
J

Joanna Carter [TeamB]

"Luc Vaillant" <[email protected]> a écrit dans le
message de news: (e-mail address removed)...

|I try to compare to values of generic value type T in a generic class as
| follow:
|
| public class C<T> where T : struct
| {
| private T value1;
| private T value2;
|
| C(T value1, T value2)
| {
| this.value1 = value1;
| this.value2 = value2;
| }
|
| public void SomeMethod()
| {
| if (value1 != value2)
| DoSomething();
| }
| }
|
| and I got the following message at compile time :
|
| "Operator '!=' cannot be applied to operands of type 'T' and 'T'"

You cannot expect T to support the == or != operators because some types may
not have overloaded them. If you are wanting to compare two Ts in the
generic class then you need to use Equals(...)

However, if you need to compare two instances of your generic class then you
nee to supply operator overloads like this :

public class C<T> where T : struct
{
private T value;

public override bool Equals(object obj)
{
return value.Equals(((C<T>) obj).value);
}

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

public static bool operator ==(C<T> lhs, C<T> rhs)
{
return lhs.value.Equals(rhs.value);
}

public static bool operator !=(C<T> lhs, C<T> rhs)
{
return ! lhs.value.Equals(rhs.value);
}
}

Joanna
 
G

Guest

Sorry, but I don't anderstand... any example ?


Nicholas Paldino said:
Luc,

How are you losing the advantage of generics? Generics doesn't lift the
type operators from the type. In other words, if you overload the ==
operator (or != operator in this case), that is NOT visible to your generic
class.

In order to get around it, you will have to create an interface which
exposes the operations, and performs them (instead of using == or !=).
Either that, or you assign a type to the class internally that will handle
the operations based on the type.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Luc Vaillant said:
I try to compare to values of generic value type T in a generic class as
follow:

public class C<T> where T : struct
{
private T value1;
private T value2;

C(T value1, T value2)
{
this.value1 = value1;
this.value2 = value2;
}

public void SomeMethod()
{
if (value1 != value2)
DoSomething();
}
}

and I got the following message at compile time :

"Operator '!=' cannot be applied to operands of type 'T' and 'T'"

Ok, I can use the following code :

if (value1.Equals(value2) == false)
DoSomething();

but doing so, I'm loosing all the advantage of generics
==> value1 and value2 are boxed before comparison occurs...

It was already the case for variable initialisation, I need to cast a
value
to Object before it can be cast back to T (see : 12/29/2005 post "Generics
limitation on .Net") :

value1 = (T)(Object)Int32.MinValue;

since it was used once in my class, I didn't care about extra
boxing/unboxing operation.

But value1 vs value2 comparison occurs in a loop in real situation (I mean
in my real program) :

for (Int32 i = value1.Length; i-- != 0; i++)
{
if (value1 != value2)
DoSomething();
}

The question is : Does generics really usefull in such sitautions ?

 
G

Guest

You cannot expect T to support the == or != operators because some types may
not have overloaded them. If you are wanting to compare two Ts in the
generic class then you need to use Equals(...)

So, I'm loosing (Speed) advantage of generics because of boxing operations...

I explain :

If using the two class definition bellow :

A<int> classA = new A<int>();
B classB = new B();

B.SomeComparison(12345) should be faster than A.SomeComparison(12345)
because boxing operations are already done.
Of course, class initialization is slower for class B because values are
boxed into ArrayList, but this is done only once.

public class A<T> where T : struct
{
private List<T> myList;

public A()
{
// Initializing myList...
}

public void SomeComparison(T aValue)
{
Object boxedValue = (Object)aValue;

for (int i = myList.Count; i-- != 0; )
{
if (myList.Equals(boxedValue))
DoSomething();
}
}

public class B
{
private ArrayList myList;

public B()
{
// Initializing myList...
}

public void SomeComparison(int aValue)
{
Object boxedValue = (Object)aValue;

for (int i = myList.Count; i-- != 0; )
{
if (myList.Equals(boxedValue))
DoSomething();
}
}
 
F

Frans Bouma [C# MVP]

Luc said:
I try to compare to values of generic value type T in a generic class
as follow:

public class C<T> where T : struct
{
private T value1;
private T value2;

C(T value1, T value2)
{
this.value1 = value1;
this.value2 = value2;
}

public void SomeMethod()
{
if (value1 != value2)
DoSomething();
}
}

and I got the following message at compile time :

"Operator '!=' cannot be applied to operands of type 'T' and 'T'"

Ok, I can use the following code :

if (value1.Equals(value2) == false)
DoSomething();

but doing so, I'm loosing all the advantage of generics
==> value1 and value2 are boxed before comparison occurs...

It was already the case for variable initialisation, I need to cast a
value to Object before it can be cast back to T (see : 12/29/2005
post "Generics limitation on .Net") :

value1 = (T)(Object)Int32.MinValue;

since it was used once in my class, I didn't care about extra
boxing/unboxing operation.

But value1 vs value2 comparison occurs in a loop in real situation (I
mean in my real program) :

for (Int32 i = value1.Length; i-- != 0; i++)
{
if (value1 != value2)
DoSomething();
}

The question is : Does generics really usefull in such sitautions ?


answer: no.

MS didn't implement a filter spec for static defined operator
overloads so you can specify them in a where clause for the generic
type. This thus means the compiler doesn't know for sure the generic
type implements the operators used in the code.

It's unfortunate, but not solvable, you have to work around it for now.

Frans

--
 
G

Guest

Hi Frans,

I found a solution to my problem:

class MyComp : IComparer<short>, IComparer<int>
{
public int Compare(int x, int y) { return x - y; }
public int Compare(short x, short y) { return x - y; }
}

class GenClass<T, I> where I : IComparer<T>, new()
{
private IComparer<T> comparer = new I();

public void SomeMethod(T value1, T value2)
{
if (comparer.Compare(value1, value2) == 0)
DoSomething();
}
}

Thanks
Luc

Frans Bouma said:
Luc said:
I try to compare to values of generic value type T in a generic class
as follow:

public class C<T> where T : struct
{
private T value1;
private T value2;

C(T value1, T value2)
{
this.value1 = value1;
this.value2 = value2;
}

public void SomeMethod()
{
if (value1 != value2)
DoSomething();
}
}

and I got the following message at compile time :

"Operator '!=' cannot be applied to operands of type 'T' and 'T'"

Ok, I can use the following code :

if (value1.Equals(value2) == false)
DoSomething();

but doing so, I'm loosing all the advantage of generics
==> value1 and value2 are boxed before comparison occurs...

It was already the case for variable initialisation, I need to cast a
value to Object before it can be cast back to T (see : 12/29/2005
post "Generics limitation on .Net") :

value1 = (T)(Object)Int32.MinValue;

since it was used once in my class, I didn't care about extra
boxing/unboxing operation.

But value1 vs value2 comparison occurs in a loop in real situation (I
mean in my real program) :

for (Int32 i = value1.Length; i-- != 0; i++)
{
if (value1 != value2)
DoSomething();
}

The question is : Does generics really usefull in such sitautions ?


answer: no.

MS didn't implement a filter spec for static defined operator
overloads so you can specify them in a where clause for the generic
type. This thus means the compiler doesn't know for sure the generic
type implements the operators used in the code.

It's unfortunate, but not solvable, you have to work around it for now.

Frans

--
 
J

Joanna Carter [TeamB]

"Luc Vaillant" <[email protected]> a écrit dans le
message de news: (e-mail address removed)...

| I found a solution to my problem:
|
| class MyComp : IComparer<short>, IComparer<int>
| {
| public int Compare(int x, int y) { return x - y; }
| public int Compare(short x, short y) { return x - y; }
| }
|
| class GenClass<T, I> where I : IComparer<T>, new()
| {
| private IComparer<T> comparer = new I();
|
| public void SomeMethod(T value1, T value2)
| {
| if (comparer.Compare(value1, value2) == 0)
| DoSomething();
| }
| }

Well, I was obviously on the right track suggesting IComparable<T>; given
that yours is not the only question I was thinking about, at least that may
have pushed you in the direction of using IComparer<T> :)

If you think the advice is worth taking :), but for others benefit anyway,
you might like to take care if you wanted to apply this to floating point
numbers as they can throw unpredictable results when checking for equality
of calculated values compared with constant values.

So you see, generics did not have the limitations you thought, you just had
to get inventive and use what was available :)

Joanna
 
J

Jon Skeet [C# MVP]

Luc Vaillant said:
I found a solution to my problem:

class MyComp : IComparer<short>, IComparer<int>
{
public int Compare(int x, int y) { return x - y; }
public int Compare(short x, short y) { return x - y; }
}

class GenClass<T, I> where I : IComparer<T>, new()
{
private IComparer<T> comparer = new I();

public void SomeMethod(T value1, T value2)
{
if (comparer.Compare(value1, value2) == 0)
DoSomething();
}
}

Do you actually need to provide an IComparer<T>? int and short both
implement IComparable<themselves>. Can't you just use:

class GenClass<T> where T : IComparable<T>,
{
public void SomeMethod(T value1, T value2)
{
if (value1.CompareTo(value2) == 0)
DoSomething();
}
}

I don't believe that involves any boxing - at least, it doesn't seem to
induce any garbage collections in the following program:

using System;

class GenClass<T> where T : IComparable<T>
{
public void SomeMethod(T value1, T value2)
{
if (value1.CompareTo(value2) == 0)
DoSomething();
// object o = value1;
}

void DoSomething()
{
}
}

public class Test
{
static void Main()
{
Console.WriteLine ("Ready?");
Console.ReadLine();
GenClass<int> test = new GenClass<int>();

for (int i=0; i < 10000000; i++)
{
test.SomeMethod (1, 2);
}
Console.WriteLine ("Finished");
Console.ReadLine();
}
}

If you uncomment the commented out line to force boxing each iteration,
you'll see lots of Gen0 collections in PerfMon. With it commented out,
you don't see any (or at least I don't).
 
G

Guest

Great, I didn't knew that numeric and string implement IComparable<T> and
IEquatable<T>

Thanks a lot
 
J

Jon Skeet [C# MVP]

Luc Vaillant said:
Great, I didn't knew that numeric and string implement IComparable<T> and
IEquatable<T>

Thanks a lot

No problem. It's worth noting that I'm only pretty much repeating what
Joanna said though :)
 
J

Joanna Carter [TeamB]

"Luc Vaillant" <[email protected]> a écrit dans le
message de news: (e-mail address removed)...

| Great, I didn't knew that numeric and string implement IComparable<T> and
| IEquatable<T>

Wow, neither did I !!

Take a look at the new 2.0 help on types derived from ValueType, it's
astounding what's in there.

Joanna
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top