Ambiguous method overloading - c#

This issue has caught me out once again. Could someone provide a technical explanation as to why the following code does not produce any warnings or errors. The question you have to ask yourself is (of course) do you feel lucky?
class Program
{
static string Feeling(object o) { return "Lucky"; }
static string Feeling(string s) { return "Unlucky"; }
static void Main(string[] args)
{
Console.WriteLine("I feel " + Feeling(null));
}
}
Bonus points awarded if you know which method will be called without running the code.
And just to add insult, it doesn't just happen with null parameters:
class Program
{
static string Feeling(int i) { return "Lucky"; }
static string Feeling(uint i) { return "Unlucky"; }
static void Main(string[] args)
{
Console.WriteLine("I feel " + Feeling(7));
}
}

First example: null argument
In the first case it will call the string overload. null matches both object and string, but string is the more specific/derived type. Thus it chooses string.
Check Eric Lippert's post How does the method overload resolution system decide which method to call when a null value is passed? for a longer explanation for this part of overload resolution.
Now we must determine the best of the applicable candidates. The bestness rules are complicated, but the short version is that more specific is better than less specific.
Second example: integer literal
In the second case it'll choose the first overload, because the literal 7 is int. If you had used 7u it would have been uint and thus the second overload would be preferred.
Integer literals have a well defined type(even if they allow more implicit conversions than normal integral values). You can use suffixes like u for unsigned, or l for long to influence that type. Or you can add an explicit cast.
While normally an int wouldn't be implicitly convertible to uint, this is an integer constant which is in the valid range of uint, and the C# compiler has an extra rule to allow implicit conversions between integer constants, provided the constant fits the target's range.
One again Eric explains the details: Why does this implicit conversion from int to uint work?
A constant expression of type int can be converted to type sbyte, byte, short, ushort, uint, or ulong, provided the value of the constant-expression is within the range of the destination type. A constant expression of type long can be converted to type ulong, provided the value of the constant expression is not negative.
In both examples one overload is clearly the best, as far as the C# compiler is concerned, and thus you don't get an ambiguous overloading error.
Personally I think that the first example should give a warning, but either the C# team disagrees, or they simply didn't have time to add that heuristic.

The simple answer is that it doesn't give any errors or warnings because it's entirely valid code by the C# spec.
The relevant section of the C# 4 spec is 7.5.3 in general (for the whole process), and 7.5.3.2 to determine which applicable function member is better when the first phase has found more than one. (The subsequent sections such as 7.5.3.5 give details about "better conversion targets" etc.)
Trying to explain the rules absolutely correctly but in a short space would be hard to say the least, unfortunately. I suggest you look through that bit of the spec yourself very carefully.

Related

Why can conversion "(long)(object)" from a type parameter be compiled?

From C# 5.0 Language Specification:
The above rules do not permit a direct explicit conversion from an
unconstrained type parameter to a non-interface type, which might be
surprising. The reason for this rule is to prevent confusion and make
the semantics of such conversions clear. For example, consider the
following declaration:
class X<T>
{
public static long F(T t) {
return (long)t; // Error
}
}
If the direct explicit conversion of t to int were permitted, one
might easily expect that X<int>.F(7) would return 7L. However, it
would not, because the standard numeric conversions are only
considered when the types are known to be numeric at binding-time.
In order to make the semantics clear, the above example must instead
be written:
class X<T>
{
public static long F(T t) {
return (long)(object)t; // Ok, but will only work when T is long
}
}
This code will now compile but executing X<int>.F(7) would then
throw an exception at run-time, since a boxed int cannot be converted
directly to a long.
Why does adding (object) make compilation work?
In the first example, if I am correct, (long) in (long)t means the standard numeric conversion without ambiguity, which requires the actual type of t to be a numeric type which can be converted to long by (long). Since there is no guarantee about the actual type of t, the compilation fails.
In the second example,
Does (long) in (long)(object)t mean unboxing conversion without being ambiguous with other kind of conversion?
Does (long) in (long)(object)t require that (object)t be a boxed long? But there is no guarantee that (object)t must be a boxed long, so why does the compilation not fail?
Thanks.

C# overload is puzzled [duplicate]

today I discovered a very strange behavior with C# function overloading. The problem occurs when I have a method with 2 overloads, one accepting Object and the other accepting Enum of any type. When I pass 0 as parameter, the Enum version of the method is called. When I use any other integer value, the Object version is called. I know this can be easilly fixed by using explicit casting, but I want to know why the compiler behaves that way. Is this a bug or just some strange language rule I don't know about?
The code below explains the problem (checked with runtime 2.0.50727)
Thanks for any help on this,
Grzegorz Kyc
class Program
{
enum Bar
{
Value1,
Value2,
Value3
}
static void Main(string[] args)
{
Foo(0);
Foo(1);
Console.ReadLine();
}
static void Foo(object a)
{
Console.WriteLine("object");
}
static void Foo(Bar a)
{
Console.WriteLine("enum");
}
}
It may be that you're not aware that there's an implicit conversion from a constant1 of 0 to any enum:
Bar x = 0; // Implicit conversion
Now, the conversion from 0 to Bar is more specific than the conversion from 0 to object, which is why the Foo(Bar) overload is used.
Does that clear everything up?
1 There's actually a bug in the Microsoft C# compiler which lets it be any zero constant, not just an integer:
const decimal DecimalZero = 0.0m;
...
Bar x = DecimalZero;
It's unlikely that this will ever be fixed, as it could break existing working code. I believe Eric Lippert has a two blog posts which go into much more detail.
The C# specification section 6.1.3 (C# 4 spec) has this to say about it:
An implicit enumeration conversion
permits the decimal-integer-literal 0
to be converted to any enum-type and
to any nullable-type whose underlying
type is an enum-type. In the latter
case the conversion is evaluated by
converting to the underlying enum-type
and wrapping the result (§4.1.10).
That actually suggests that the bug isn't just in allowing the wrong type, but allowing any constant 0 value to be converted rather than only the literal value 0.
EDIT: It looks like the "constant" part was partially introduced in the C# 3 compiler. Previously it was some constant values, now it looks like it's all of them.
I know I have read somewhere else that the .NET system always treats zero as a valid enumeration value, even if it actually isn't. I will try to find some reference for this...
OK, well I found this, which quotes the following and attributes it to Eric Gunnerson:
Enums in C# do dual purpose. They are used for the usual enum use, and they're also used for bit fields. When I'm dealing with bit fields, you often want to AND a value with the bit field and check if it's true.
Our initial rules meant that you had to write:
if ((myVar & MyEnumName.ColorRed) != (MyEnumName) 0)
which we thought was difficult to read. One alernative was to define a zero entry:
if ((myVar & MyEnumName.ColorRed) != MyEnumName.NoBitsSet)
which was also ugly.
We therefore decided to relax our rules a bit, and permit an implicit conversion from the literal zero to any enum type, which allows you to write:
if ((myVar & MyEnumName.ColorRed) != 0)
which is why PlayingCard(0, 0) works.
So it appears that the whole reason behind this was to simply allow equating to zero when checking flags without having to cast the zero.

Strange (possibly wrong?) C# compiler behavior with method overloading and enums

today I discovered a very strange behavior with C# function overloading. The problem occurs when I have a method with 2 overloads, one accepting Object and the other accepting Enum of any type. When I pass 0 as parameter, the Enum version of the method is called. When I use any other integer value, the Object version is called. I know this can be easilly fixed by using explicit casting, but I want to know why the compiler behaves that way. Is this a bug or just some strange language rule I don't know about?
The code below explains the problem (checked with runtime 2.0.50727)
Thanks for any help on this,
Grzegorz Kyc
class Program
{
enum Bar
{
Value1,
Value2,
Value3
}
static void Main(string[] args)
{
Foo(0);
Foo(1);
Console.ReadLine();
}
static void Foo(object a)
{
Console.WriteLine("object");
}
static void Foo(Bar a)
{
Console.WriteLine("enum");
}
}
It may be that you're not aware that there's an implicit conversion from a constant1 of 0 to any enum:
Bar x = 0; // Implicit conversion
Now, the conversion from 0 to Bar is more specific than the conversion from 0 to object, which is why the Foo(Bar) overload is used.
Does that clear everything up?
1 There's actually a bug in the Microsoft C# compiler which lets it be any zero constant, not just an integer:
const decimal DecimalZero = 0.0m;
...
Bar x = DecimalZero;
It's unlikely that this will ever be fixed, as it could break existing working code. I believe Eric Lippert has a two blog posts which go into much more detail.
The C# specification section 6.1.3 (C# 4 spec) has this to say about it:
An implicit enumeration conversion
permits the decimal-integer-literal 0
to be converted to any enum-type and
to any nullable-type whose underlying
type is an enum-type. In the latter
case the conversion is evaluated by
converting to the underlying enum-type
and wrapping the result (§4.1.10).
That actually suggests that the bug isn't just in allowing the wrong type, but allowing any constant 0 value to be converted rather than only the literal value 0.
EDIT: It looks like the "constant" part was partially introduced in the C# 3 compiler. Previously it was some constant values, now it looks like it's all of them.
I know I have read somewhere else that the .NET system always treats zero as a valid enumeration value, even if it actually isn't. I will try to find some reference for this...
OK, well I found this, which quotes the following and attributes it to Eric Gunnerson:
Enums in C# do dual purpose. They are used for the usual enum use, and they're also used for bit fields. When I'm dealing with bit fields, you often want to AND a value with the bit field and check if it's true.
Our initial rules meant that you had to write:
if ((myVar & MyEnumName.ColorRed) != (MyEnumName) 0)
which we thought was difficult to read. One alernative was to define a zero entry:
if ((myVar & MyEnumName.ColorRed) != MyEnumName.NoBitsSet)
which was also ugly.
We therefore decided to relax our rules a bit, and permit an implicit conversion from the literal zero to any enum type, which allows you to write:
if ((myVar & MyEnumName.ColorRed) != 0)
which is why PlayingCard(0, 0) works.
So it appears that the whole reason behind this was to simply allow equating to zero when checking flags without having to cast the zero.

Why do I have to typecast an int in a ternary expression? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Conditional operator cannot cast implicitly?
I have run into a peculiar situation and want to know why I have to do it. I'm using .NET 3.5.
This works:
short foo;
if (isValid)
foo = -1;
else
foo = getFoo();
This does not work:
short foo;
foo = isValid ? -1 : getFoo();
I have to typecast -1:
short foo;
foo = isValid ? (short)-1 : getFoo();
What does the ternary expression do differently? It considers the -1 to be an int that needs to be cast into a short. But why?
A few things.
First off, the conditional operator is a ternary operator, not a tertiary operator.
Second, I note that in your code samples the two code samples which are intended to be equivalent are not:
short foo;
if (isValid)
foo = -1;
else
getFoo();
is not the same as
short foo = isValid ? (short)-1 : getFoo();
The former leaves foo unassigned if isValid is false. The latter assigns foo regardless of the value of isValid.
I assume that you meant
short foo;
if (isValid)
foo = -1;
else
foo = getFoo();
and that furthermore, getFoo() returns short.
The question is why the conversion in the conditional operator without the type cast is illegal but in the consequence of the if statement is legal.
It is legal in the if statement because section 6.1.9 of the specification states:
A constant-expression of type int can be converted to type sbyte, byte, short, ushort, uint, or ulong, provided the value of the constant-expression is within the range of the destination type.
-1 is a constant expression of type int that is in the range of short, so it can be converted to short implicitly.
So why is the conditional expression form bogus?
The first thing we have to establish clearly is the rule that the type of the conditional expression is determined from its contents, not from its context. The type of the expression on the right side of an assignment does not depend on what it is being assigned to! Suppose you had
short M(short x){...}
int M(int x){...}
short y = M(-1);
I don't think you'd expect overload resolution to say "well, I'd normally pick M(int) because -1 is an int, but no, I'll pick M(short) instead because otherwise the assignment won't work." Overload resolution doesn't know anything about where the result is going. It's job is to work out what the right overload is based on the arguments given, not based on the context of the call.
Determining the type of the conditional expression works the same way. We don't look at the type its going to, we look at the types that are in the expression.
OK, so we have established that the fact that this is being assigned to short is irrelevant for determining the type of the expression. But that still leaves the question "Why is the type of the conditional expression int rather than short?"
That is a very good question. Let's go to the spec.
The second and third operands, x and y, of the ?: operator control the type of the conditional expression.
If has type X and y has type Y then:
If an implicit conversion exists from X to Y, but not from Y to X, then Y is the type of the conditional expression.
If an implicit conversion exists from Y to X, but not from X to Y, then X is the type of the conditional expression.
Otherwise, no expression type can be determined, and a compile-time error occurs.
In this case the operands both have a type. (The verbiage in there about "if x has a type..." is for the case where you have null or a lambda in there; those don't have types!) The first operand is of type int, the second is of type short.
An implicit conversion exists from short to int, but not from int to short. Therefore the type of the conditional expression is int, which cannot be assigned to short.
Now, one could say that this algorithm is not as good as it could be. We could greatly complicate the algorithm to deal with all the cases where there were two possible "candidate" types -- in this case, int and short are both plausible candidates because both branches are convertible to both int and short when considered as specific expressions, rather than simply as having types. We could say in that case that the smaller of the two types was the preferred type.
(Sometimes in C# we say that the more general of two types is the better type, but in this case you would want us to pick the more specific. The language is not consistent in this particular design aspect, unfortunately; I personally would rather we always choose the more specific, but there are type inference scenarios where that would be a breaking change now.)
I considered doing that back in 2006. When designing the behaviour of how LINQ deals with situations where there are multiple types to choose from and one must be picked as "the best" we noticed that the conditional operator already had to solve this problem, and that furthermore, in C# 2 it was not actually implemented according to spec. There was a long debate about this and we ended up making some minor changes to the specification for the conditional operator to bring it more into line with its implemented (and desired) behaviour. However we decided to not take the larger breaking change of tweaking the algorithm to use the smaller of two possible types when there were several to choose from.
For some musings on this problem, see my posts from 2006 on it:
Type inference woes, part one
Type inference woes, part two
Type inference woes, part three
Because -1 by default is an integer. It's a lot safer for the compiler to tell you that you have to explicitly tell it what to do, than it is for the compiler to make an assumption as to what you want done.
You're example is pretty straight forward. With a little extra work, the compiler could obviously see that you want -1 to be a short. There are all the edge cases that go along with implicit conversion that aren't so simple though. If you add a rule for the compiler to make an assumption about what you want, you have to apply it to every case not just one and that is where it gets difficult.
As a note you should check out Eric Lippert's blog as I know that he covers why the compiler doesn't make such assumptions.
A conditional operator applied to an int and a short is of type int; the compiler will not infer the expression's type from the type you assign it to.
You cannot implicitly cast this short expression to an int.
The conditional operator imposes that both possible result expressions be of the same type. In this case the left side is an int and the right side is a short returned by getPoo method. Since it's always safe to convert a short to an int the compiler chooses that the result of the operation will be an int.
So the result will be the assignment of an int to a short and that's why you need to explicitly cast it to a short.
If you explicitly use an if/else approach you will be assigning a literal integer to a short which allows the compiler to verify that the literal integer is safely assigned to a short without the need of a explicit cast.
For an inside explanation take a look at:
Cast operators do not obey the distributive law

What is the difference between Convert.ToInt32 and (int)?

The following code throws an compile-time error like
Cannot convert type 'string' to 'int'
string name = Session["name1"].ToString();
int i = (int)name;
whereas the code below compiles and executes successfully:
string name = Session["name1"].ToString();
int i = Convert.ToInt32(name);
I would like to know:
Why does the the first code generate a compile-time error?
What's the difference between the 2 code snippets?
(int)foo is simply a cast to the Int32 (int in C#) type. This is built into the CLR and requires that foo be a numeric variable (e.g. float, long, etc.) In this sense, it is very similar to a cast in C.
Convert.ToInt32 is designed to be a general conversion function. It does a good deal more than casting; namely, it can convert from any primitive type to a int (most notably, parsing a string). You can see the full list of overloads for this method here on MSDN.
And as Stefan Steiger mentions in a comment:
Also, note that on a numerical level, (int) foo truncates foo (ifoo = Math.Floor(foo)), while Convert.ToInt32(foo) uses half to even rounding (rounds x.5 to the nearest EVEN integer, meaning ifoo = Math.Round(foo)). The result is thus not just implementation-wise, but also numerically not the same.
(this line relates to a question that was merged) You should never use (int)someString - that will never work (and the compiler won't let you).
However, int int.Parse(string) and bool int.TryParse(string, out int) (and their various overloads) are fair game.
Personally, I mainly only use Convert when I'm dealing with reflection, so for me the choice is Parse and TryParse. The first is when I expect the value to be a valid integer, and want it to throw an exception otherwise. The second is when I want to check if it is a valid integer - I can then decide what to do when it is/isn't.
To quote from this Eric Lippert article:
Cast means two contradictory things: "check to see if this object really is of this type, throw if it is not" and "this object is not of the given type; find me an equivalent value that belongs to the given type".
So what you were trying to do in 1.) is assert that yes a String is an Int. But that assertion fails since String is not an int.
The reason 2.) succeeds is because Convert.ToInt32() parses the string and returns an int. It can still fail, for example:
Convert.ToInt32("Hello");
Would result in an Argument exception.
To sum up, converting from a String to an Int is a framework concern, not something implicit in the .Net type system.
A string cannot be cast to an int through explicit casting. It must be converted using int.Parse.
Convert.ToInt32 basically wraps this method:
public static int ToInt32(string value)
{
if (value == null)
{
return 0;
}
return int.Parse(value, CultureInfo.CurrentCulture);
}
You're talking about a C# casting operation vs .NET Conversion utilities
C# Language-level casting uses parenthesis - e.g. (int) - and conversion support for it is limited, relying on implicit compatibility between the types, or explicitly defined instructions by the developer via conversion operators.
Many conversion methods exist in the .NET Framework, e.g. System.Convert, to allow conversion between same or disparate data types.
(Casting) syntax works on numeric data types, and also on "compatible" data types. Compatible means data types for which there is a relationship established through inheritance (i.e. base/derived classes) or through implementation (i.e. interfaces).
Casting can also work between disparate data types that have conversion operators defined.
The System.Convert class on the other hand is one of many available mechanisms to convert things in the general sense; it contains logic to convert between disparate, known, data types that can be logically changed from one form into another.
Conversion even covers some of the same ground as casting by allowing conversion between similar data types.
Remember that the C# language has its own way of doing some things.
And the underlying .NET Framework has its own way of doing things, apart from any programming language.
(Sometimes they overlap in their intentions.)
Think of casting as a C# language-level feature that is more limited in nature, and conversion via the System.Convert class as one of many available mechanisms in the .NET framework to convert values between different kinds.
There is not a default cast from string to int in .NET. You can use int.Parse() or int.TryParse() to do this. Or, as you have done, you can use Convert.ToInt32().
However, in your example, why do a ToString() and then convert it back to an int at all? You could simply store the int in Session and retrieve it as follows:
int i = Session["name1"];
Just a brief extra: in different circumstances (e.g. if you're converting a double, &c to an Int32) you might also want to worry about rounding when choosing between these two. Convert.Int32 will use banker's rounding (MSDN); (int) will just truncate to an integer.
1) C# is type safe language and doesn't allow you to assign string to number
2) second case parses the string to new variable.
In your case if the Session is ASP.NET session than you don't have to store string there and convert it back when retrieving
int iVal = 5;
Session[Name1] = 5;
int iVal1 = (int)Session[Name1];
This is already discussed but I want to share a dotnetfiddle.
If you are dealing with arithmetic operations and using float, decimal, double and so on, you should better use Convert.ToInt32().
using System;
public class Program
{
public static void Main()
{
double cost = 49.501;
Console.WriteLine(Convert.ToInt32(cost));
Console.WriteLine((int)cost);
}
}
Output
50
49
https://dotnetfiddle.net/m3ddDQ
Convert.ToInt32
return int.Parse(value, CultureInfo.CurrentCulture);
but (int) is type cast, so (int)"2" will not work since you cannot cast string to int. but you can parse it like Convert.ToInt32 do
The difference is that the first snippet is a cast and the second is a convert. Although, I think perhaps the compiler error is providing more confusion here because of the wording. Perhaps it would be better if it said "Cannot cast type 'string' to 'int'.
This is old, but another difference is that (int) doesn't round out the numbers in case you have a double ej: 5.7 the ouput using (int) will be 5 and if you use Convert.ToInt() the number will be round out to 6.

Categories