By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,916 Members | 1,328 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,916 IT Pros & Developers. It's quick & easy.

What does this mean(Generics)

P: n/a
Hello!

It says "Another limitation that you need to be aware of is that using the
operator == and != are
only permitted when comparing a value of a type supplied to a generic type
to null.
That is, the following code works.
Here if T is a value type then it is always assumed to be non-null, so in
the above
code Compare always return true;"

The question is what does they mean with the text saying "using the operator
== and != are
only permitted when comparing a value of a type supplied to a generic type
to null."

public bool Compare(T op1, T op2)
{
if (op1 != null && op2 != null)
{
return true;
}
else
{
return false;
}
}

//Tony
Jun 27 '08 #1
Share this Question
Share on Google+
14 Replies


P: n/a
On Jun 18, 1:17*pm, "Tony" <johansson.anders...@telia.comwrote:
It says "Another limitation that you need to be aware of is that using the
operator == and != are
only permitted when comparing a value of a type supplied to a generic type
to null.
That is, the following code works.
Here if T is a value type then it is always assumed to be non-null, so in
the above
code Compare always return true;"

The question is what does they mean with the text saying "using the operator
== and != are
only permitted when comparing a value of a type supplied to a generic type
to null."
It means that if T is unconstrained you can't do:

T foo = ...;
T bar = ...;

if (foo == bar)

If you constrain T to be a reference type (i.e. use "where T : class")
then reference identity comparisons will be used and you can compare
two values

If you constrain T to be derived from a type which overloads == and !=
then those overloads will be used. This is *not* polymorphic - only
overloads the compiler can guarantee at compile-time are used. For
instance, if you had a constraint "T : IEnumerable<char>" and used
"string" then == would still mean reference identity, rather than
using the == overloaded for string.

Jon
Jun 27 '08 #2

P: n/a
What I find interesting about this example is that if you constrain T
to be a “struct” then you will get a compile error.

So why is it that when T its unconstrained and it can be a “class” –
or- **struct** you don’t get a compile error?
On Jun 18, 7:24*am, "Jon Skeet [C# MVP]" <sk...@pobox.comwrote:
On Jun 18, 1:17*pm, "Tony" <johansson.anders...@telia.comwrote:
It says "Another limitation that you need to be aware of is that using the
operator == and != are
only permitted when comparing a value of a type supplied to a generic type
to null.
That is, the following code works.
Here if T is a value type then it is always assumed to be non-null, so in
the above
code Compare always return true;"
The question is what does they mean with the text saying "using the operator
== and != are
only permitted when comparing a value of a type supplied to a generic type
to null."

It means that if T is unconstrained you can't do:

T foo = ...;
T bar = ...;

if (foo == bar)

If you constrain T to be a reference type (i.e. use "where T : class")
then reference identity comparisons will be used and you can compare
two values

If you constrain T to be derived from a type which overloads == and !=
then those overloads will be used. This is *not* polymorphic - only
overloads the compiler can guarantee at compile-time are used. For
instance, if you had a constraint "T : IEnumerable<char>" and used
"string" then == would still mean reference identity, rather than
using the == overloaded for string.

Jon
Jun 27 '08 #3

P: n/a
<qg**********@mailinator.comwrote:
What I find interesting about this example is that if you constrain T
to be a =3Fstruct=3F then you will get a compile error.

So why is it that when T its unconstrained and it can be a =3Fclass=3F =3F
or- **struct** you don=3Ft get a compile error?
When it's unconstrained and at execution time T is a struct, then the
comparison with null always fails - even for default(T). (That's a
handy way of telling at execution time whether or not it *is* a struct,
in fact.)

If you explicitly constrain it to being a struct, then the comparison
is pointless as you always know the answer.

--
Jon Skeet - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Jun 27 '08 #4

P: n/a
I am ok with what you are saying, however, it was my impression that
the whole reason for constraining a generic parameter was so that the
compiler could resolve any issues during compiling time.

If the compiler allows the code to compile without a constraint
(therefore allowing the generic parameter to by “class” –or-
“struct”), then in my opinion it should allow it to compile with a
constraint of “struct” (whether that makes sense or not) otherwise
this is a double standard.

If I wanted to know if the generic parameter is a “class” or a
“struct” then I could use “typeof(T).IsClass”.

I am still not clear why this is allowed. Am I just not looking a this
the right way?

Thanks.

On Jun 18, 3:01*pm, Jon Skeet [C# MVP] <sk...@pobox.comwrote:
*<qglyirnyf...@mailinator.comwrote:
What I find interesting about this example is that if you constrain T
to be a =3Fstruct=3F then you will get a compile error.
So why is it that when T its unconstrained and it can be a =3Fclass=3F =3F
or- **struct** you don=3Ft get a compile error?

When it's unconstrained and at execution time T is a struct, then the
comparison with null always fails - even for default(T). (That's a
handy way of telling at execution time whether or not it *is* a struct,
in fact.)

If you explicitly constrain it to being a struct, then the comparison
is pointless as you always know the answer.

--
Jon Skeet - <sk...@pobox.com>
Web site:http://www.pobox.com/~skeet*
Blog:http://www.msmvps.com/jon.skeet
C# in Depth:http://csharpindepth.com
Jun 27 '08 #5

P: n/a
<qg**********@mailinator.comwrote:
I am ok with what you are saying, however, it was my impression that
the whole reason for constraining a generic parameter was so that the
compiler could resolve any issues during compiling time.
To some extent. I'd say the reasons are:

1) Allow *more* to be done by the compiler within the type/method,
because it has more information about what the type parameter might
be at execution time.

2) Constrain clients so they'll only use the type/method with
appropriate type arguments.
If the compiler allows the code to compile without a constraint
(therefore allowing the generic parameter to by =3Fclass=3F =3For-
=3Fstruct=3F), then in my opinion it should allow it to compile with a
constraint of =3Fstruct=3F (whether that makes sense or not) otherwise
this is a double standard.
No - it's using the fact that it's got more information to prohibit a
redundant comparison. The comparison *isn't* redundant when the type is
unconstrained, as it will have different results depending on the value
and the type parameter.
If I wanted to know if the generic parameter is a =3Fclass=3F or a
=3Fstruct=3F then I could use =3Ftypeof(T).IsClass=3F.
You could, but I *suspect* it takes longer. In particular, the JIT can
work out that

if (default(T) == null)

will always be false for value types and true for reference types
without knowing anything about the Type class. I would hope that it
would take advantage of that and optimise away the comparison (and
potentially the code within the subsequent block).

Now it *could* do that through knowledge of the IsClass property, but
it's a bit further away from its normal type of optimisation, IMO.
I am still not clear why this is allowed. Am I just not looking a this
the right way?
Would you rather the comparison was prohibited completely for
unconstrained type parameters? While I can't *immediately* think of a
time I've used it, I'm sure I have...

--
Jon Skeet - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Jun 27 '08 #6

P: n/a
Would you rather the comparison was prohibited completely for
unconstrained type parameters?

I think it should be either *complete prohibited* or *completely
allowed* to compare value types to nulls.

Take a look at the following snippet of code:

int i = 8;
bool b = (i == null);

If you compile this code the compiler will compile it successfully and
only issue a warning to the effect that the statement is always false.
So again, it ok to let it fly here but not on the example we have been
talking about.

In my opinion, the compiler should either allow a value type be
compared to a null or not allow it (whether that makes sense or not).
It should not pick and choose sometime yes, sometimes no based on some
unknown reasoning.

But something tells me you are not ok with that or are you? :)
Jun 27 '08 #7

P: n/a
<qg**********@mailinator.comwrote:
Would you rather the comparison was prohibited completely for
unconstrained type parameters?

I think it should be either *complete prohibited* or *completely
allowed* to compare value types to nulls.

Take a look at the following snippet of code:

int i = 8;
bool b = (i == null);

If you compile this code the compiler will compile it successfully and
only issue a warning to the effect that the statement is always false.
So again, it ok to let it fly here but not on the example we have been
talking about.
Well, that's a somewhat completely different issue - that's doing an
implicit conversion from int to int? and then comparing *that* with
null.
In my opinion, the compiler should either allow a value type be
compared to a null or not allow it (whether that makes sense or not).
It should not pick and choose sometime yes, sometimes no based on some
unknown reasoning.
It's not unknown. It's all in the spec.
But something tells me you are not ok with that or are you? :)
I'm pretty much fine with the way it is now, although the implicit
conversion above does irritate me.

--
Jon Skeet - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Jun 27 '08 #8

P: n/a
Well, that's a somewhat completely different issue - that's doing an
implicit conversion from int to int? and then comparing *that* with
null.
mmm.. the plot thickens. This calls fro doing some more research… I am
looking at the IL and seeing interesting things.

Go to go home, will post later.

Thanks for the help!
Jun 27 '08 #9

P: n/a
If you compile this code the compiler will compile it successfully and
only issue a warning to the effect that the statement is always false.
Actually, you don't always get a warning any more:
http://connect.microsoft.com/VisualS...dbackID=348850

Marc
Jun 27 '08 #10

P: n/a
On Jun 19, 8:38*am, Marc Gravell <marc.grav...@gmail.comwrote:
If you compile this code the compiler will compile it successfully and
only issue a warning to the effect that the statement is always false.

Actually, you don't always get a warning any more:http://connect.microsoft.com/VisualS...Feedback.aspx?...
Eek, that's somewhat alarming. Given that it's almost always
symptomatic of a developer misunderstanding their data, it's a really
useful warning to get...

Jon
Jun 27 '08 #11

P: n/a
Feel free to validate it independently and click some buttons to help
escalate it, then ;-p

Marc
Jun 27 '08 #12

P: n/a
On Jun 19, 9:35*am, Marc Gravell <marc.grav...@gmail.comwrote:
Feel free to validate it independently and click some buttons to help
escalate it, then ;-p
Have done so - but in testing it I found that it's not quite as bad as
it might be. It occurs with custom structs such as DateTime, but if
you try it with primitive types (e.g. int) the warning is still
raised. As the primitive types are used so much more (IME) than other
structs, that's a relief - but I'd still like to see it fixed.

Jon
Jun 27 '08 #13

P: n/a
I observed it didn't happen with primatives, which is why I posted with
a bespoke struct - I didn't think of trying DateTime/decimal. That would
have saved some typing ;-p

Cheers,

Marc
Jun 27 '08 #14

P: n/a
Jon Skeet [C# MVP] wrote:
On Jun 19, 9:35 am, Marc Gravell <marc.grav...@gmail.comwrote:
>Feel free to validate it independently and click some buttons to help
escalate it, then ;-p

Have done so - but in testing it I found that it's not quite as bad as
it might be. It occurs with custom structs such as DateTime, but if
you try it with primitive types (e.g. int) the warning is still
raised. As the primitive types are used so much more (IME) than other
structs, that's a relief - but I'd still like to see it fixed.

Jon
I can't think of an example offhand, but it seems legal, right now, to
define a meaningful operator== comparison between different types, including
between a value type and a reference type.

Oh, here's the counter-example -- IntPtr. Although inspection reveals that
IntPtr.Zero == null would indeed return false. And that not producing
either a warning or the least-surprising result is more than a little
disturbing.
Jul 18 '08 #15

This discussion thread is closed

Replies have been disabled for this discussion.