Constructor Overloading Bug?

K

Klaus Löffelmann

Hi,

does anybody know, why the second contructor isn't called in this example?
Are you able to reproduce this bug?
Thanks

Klaus

Public Class Something

Shared Sub Main()
Dim test1 As New Something("C"c, 1)
Dim test2 As New Something("String", 2)
End Sub

Sub New(ByVal aChar As Char, ByVal aByte As Byte)
Console.WriteLine("Char/Byte-Konstruktor")
End Sub

Sub New(ByVal aString As String, ByVal anInteger As Integer)
Console.WriteLine("String/Integer-Konstruktor")
End Sub

End Class
 
K

Klaus Löffelmann

....actually, it is the first constructor, that is not being called...

Klaus
 
A

Armin Zingler

Klaus Löffelmann said:
...actually, it is the first constructor, that is not being
called...

Dim test1 As New Something("C"c, 1)

The number 1 is interpreted as integer, not as byte. That's why the second
constructor is called - the Char "C"c is converted to a String because
widening conversions are allowed. Calling the first constructor would be a
narrowing conversion.

Use
Dim test1 As New Something("C"c, CByte(1))
instead.
 
M

Mattias Sjögren

Klaus,
does anybody know, why the second contructor isn't called in this example?
Are you able to reproduce this bug?


If you force the constant 1 to be a Byte (it's an Integer by default),
the first constructor will be called.

Dim test1 As New Something("C"c, CByte(1))



Mattias
 
C

Cor

Hi Klaus,

I do not know what is it theoretical, but this he does well,
Dim test1 As New Something("C"c, CByte(1))

Just if it first trys to resolve to find if it is an integer and than
threats the character as a one position string.

I hope this helps something.

Cor
 
J

Jay B. Harlow [MVP - Outlook]

Klaus,
Dim test1 As New Something("C"c, 1)
1 is an Integer literal, Char can be upgraded to a string, but an Integer
cannot be downgraded to a Byte, hence the second constructor is called.

I don't see how to specify a Byte literal itself, so try:
Dim test1 As New Something("C"c, CByte(1))

Alternatively add a third constructor (or change the first constructor),
such as:
Sub New(ByVal aChar As Char, ByVal anInteger As Integer)
Console.WriteLine("Char/Integer-Konstruktor")
End Sub

I would probably simply define two constructors Char/Integer &
String/Integer constructors to "avoid" the problem...

Hope this helps
Jay
 
K

Klaus Löffelmann

Mattias,

why do I have to force the second parameter to be a byte, when it's already
clear that I'm pushing a char, to begin with. I mean, if you declare a
"normal" procedure to take a char and you then try to give it a string, the
compiler is complaining. So why can't he then tell the difference in this
example?

Aside of that: I tried what you suggested in my project already (this is
just an excerpt), and of course converted the second parameter to a byte. It
called the string/Integer constructor, anyway. Only after I changed the
order, I got it to work. But the curious thing is: When I rechanged the
order, it suddenly could recognize the byte as a byte, and now I can't
reproduce the behaviour anymore.

However, the behaviour described in this exceprt is weird enough, isn't it?

Klaus
 
J

Jay B. Harlow [MVP - Outlook]

Klaus,
What do you mean "changed the order"?

Do you mean you made the String/Integer come before the Char/Byte in the
source?

Or that you had Integer/String & Byte/Char constructors?

As I stated in my other post, the 1 is being treated as an Integer Literal
first, VB.NET knows it can convert the Char to a string, hence it is picking
the String/Integer overload!

Is this a bug, possible! is this "by design", possible! I know enough about
implementing overloading in a compiler to understand it can be very
difficult to get overload resolution to work.

Here are a number of articles on VB.NET overload method resolution:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbls7/html/vblrfvbspec9_3_4.asp

http://msdn.microsoft.com/library/d...-us/vbcn7/html/vaconoverloadingprocedures.asp

Mostly this one:
http://msdn.microsoft.com/library/d.../en-us/vbcn7/html/vaconoverloadresolution.asp

I would say it is seeing the 1 as an integer, and according to rule 2 on the
last link is throwing away the Char/Byte overload.

Hope this helps
Jay

Klaus Löffelmann said:
Mattias,

why do I have to force the second parameter to be a byte, when it's already
clear that I'm pushing a char, to begin with. I mean, if you declare a
"normal" procedure to take a char and you then try to give it a string, the
compiler is complaining. So why can't he then tell the difference in this
example?

Aside of that: I tried what you suggested in my project already (this is
just an excerpt), and of course converted the second parameter to a byte. It
called the string/Integer constructor, anyway. Only after I changed the
order, I got it to work. But the curious thing is: When I rechanged the
order, it suddenly could recognize the byte as a byte, and now I can't
reproduce the behaviour anymore.

However, the behaviour described in this exceprt is weird enough, isn't it?

Klaus
 
K

Klaus Löffelmann

Nope,

I was wrong. Chars get promoted to Strings, when VB feels to do so. That was
my mistake.
But consistently, overloaded procedures only differing in char and string
shouldn't be allowed then, anyway.

Thanks, everybody

Klaus


Klaus Löffelmann said:
Mattias,

why do I have to force the second parameter to be a byte, when it's already
clear that I'm pushing a char, to begin with. I mean, if you declare a
"normal" procedure to take a char and you then try to give it a string, the
compiler is complaining. So why can't he then tell the difference in this
example?

Aside of that: I tried what you suggested in my project already (this is
just an excerpt), and of course converted the second parameter to a byte. It
called the string/Integer constructor, anyway. Only after I changed the
order, I got it to work. But the curious thing is: When I rechanged the
order, it suddenly could recognize the byte as a byte, and now I can't
reproduce the behaviour anymore.

However, the behaviour described in this exceprt is weird enough, isn't it?

Klaus
 
K

Klaus Löffelmann

Jay,

Sorry, I replied and then read you message - I was out of sync, so to say.
The Integer and Byte stuff was totally clear to me; it's just, as I already
pointed out, that overloading procedures just with a different char and
string parameter shouldn't be allowed then, isn't it?

Thanks for your help,

Klaus



Jay B. Harlow said:
Klaus,
What do you mean "changed the order"?

Do you mean you made the String/Integer come before the Char/Byte in the
source?

Or that you had Integer/String & Byte/Char constructors?

As I stated in my other post, the 1 is being treated as an Integer Literal
first, VB.NET knows it can convert the Char to a string, hence it is picking
the String/Integer overload!

Is this a bug, possible! is this "by design", possible! I know enough about
implementing overloading in a compiler to understand it can be very
difficult to get overload resolution to work.

Here are a number of articles on VB.NET overload method resolution:
http://msdn.microsoft.com/library/d...-us/vbcn7/html/vaconoverloadingprocedures.asp

Mostly this one:
http://msdn.microsoft.com/library/d.../en-us/vbcn7/html/vaconoverloadresolution.asp

I would say it is seeing the 1 as an integer, and according to rule 2 on the
last link is throwing away the Char/Byte overload.

Hope this helps
Jay

Klaus Löffelmann said:
Mattias,

why do I have to force the second parameter to be a byte, when it's already
clear that I'm pushing a char, to begin with. I mean, if you declare a
"normal" procedure to take a char and you then try to give it a string, the
compiler is complaining. So why can't he then tell the difference in this
example?

Aside of that: I tried what you suggested in my project already (this is
just an excerpt), and of course converted the second parameter to a
byte.
 
M

Mattias Sjögren

Klaus,
I was wrong. Chars get promoted to Strings, when VB feels to do so. That was
my mistake.
But consistently, overloaded procedures only differing in char and string
shouldn't be allowed then, anyway.

Why do you say that? Do you also think that

Sub Foo(i As Integer)

Sub Foo(i As Long)

should be disallowed, just because an Integer can implicitly promoted
to a Long?



Mattias
 
K

Klaus Löffelmann

Mattias Sjögren said:
Klaus,


Why do you say that? Do you also think that

Sub Foo(i As Integer)

Sub Foo(i As Long)

should be disallowed, just because an Integer can implicitly promoted
to a Long?

Why would I say that? The overloading resolution works fine, here, it's
unquestionable.
I just wanted to say, that to my mind the BCL sets the priority wrong in the
given example. The Integer/byte decision is not clear, granted. But actually
there is no mistake about char. All I said was that I'd rather stick to the
obvious (Char is clear, let's have the second parameter a byte then) than to
just assume (let's consider the second one an integer...) the second *and*
the first parameter (...oh, but then we have to promote the first one to a
string).

Klaus
 
J

Jay B. Harlow [MVP - Outlook]

Klaus,
The Integer and Byte stuff was totally clear to me; it's just, as I already
pointed out, that overloading procedures just with a different char and
string parameter shouldn't be allowed then, isn't it?
No!

Both Char & String are distinct types so you are allowed to overload them,
as are Byte & Integer you are also allowed to overload them. Look at all the
overloads for System.Console.Write, all "primitive" types are represented!

The "problem" with your example, is that you had a literal 1, which you
assumed was a Byte. The literal 1 is defined to be an Integer. As Armin
stated, narrowing the Integer to a Byte is "not allowed" (possible loss of
precision, the fact its a literal that fits apparently is not a
consideration) so that overload was ruled out. Which leaves the widening to
String to match the second overload the only path available.

You can add a suffix to your literals to explicitly state what the literal
is: Such as:

1S ' a short literal
1I ' an explicit integer literal
1L ' a long literal

1 ' an implicit integer literal

The "problem" that I see there is no suffix for Byte.

1B ' a byte literal?

Unfortunately B is not valid, there is no literal suffix for Byte. However!
Single, Double, and Decimal all have suffixes...

As others have pointed out you can use CByte to get the overload you want to
be selected. Also if you had the 1 in a Byte variable, the correct overload
would be called.

The short of it is: The Char/Byte overload cannot be matched with a literal
(for Byte), as there are no Byte literals!

Hope this helps
Jay
 
J

Jay B. Harlow [MVP - Outlook]

Klaus,
I just wanted to say, that to my mind the BCL sets the priority wrong in the
given example. The Integer/byte decision is not clear, granted. But actually
there is no mistake about char. All I said was that I'd rather stick to the
obvious (Char is clear, let's have the second parameter a byte then) than to
just assume (let's consider the second one an integer...) the second *and*
the first parameter (...oh, but then we have to promote the first one to a
string).
The BCL is not setting the priority here as much as VB.NET itself is setting
the priority here. Based on the rules that I gave links to earlier.

VB.NET is not assuming the second is an integer, the literal 1 is defined to
be an integer. As clearly stated in the following topic:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbls7/html/vblrfvbspec2_4_2.asp

Hence your sample is effectively:

Const c As Char = "C"c
Const i As Integer = 1

Dim test1 As New Something(c, i)

Seeing as the Integer cannot be squeezed into a Byte, while the Char can be
expanded into a String, the String/Integer overload is the one that is used!

Hope this helps
Jay


Klaus Löffelmann said:
Mattias Sjögren said:
That
was

Why do you say that? Do you also think that

Sub Foo(i As Integer)

Sub Foo(i As Long)

should be disallowed, just because an Integer can implicitly promoted
to a Long?

Why would I say that? The overloading resolution works fine, here, it's
unquestionable.
I just wanted to say, that to my mind the BCL sets the priority wrong in the
given example. The Integer/byte decision is not clear, granted. But actually
there is no mistake about char. All I said was that I'd rather stick to the
obvious (Char is clear, let's have the second parameter a byte then) than to
just assume (let's consider the second one an integer...) the second *and*
the first parameter (...oh, but then we have to promote the first one to a
string).

Klaus
 
K

Klaus Löffelmann

Yeah, you're right. I learned that the hard way.
It's already 0:00 here in Germany (OK, almost), maybe that's the reason I've
been so stubborn - actually, I'm not like that ;-)

Thanks for your help, I really appreciate it!

Klaus

Jay B. Harlow said:
Klaus,
I just wanted to say, that to my mind the BCL sets the priority wrong in the
given example. The Integer/byte decision is not clear, granted. But actually
there is no mistake about char. All I said was that I'd rather stick to the
obvious (Char is clear, let's have the second parameter a byte then)
than
to
just assume (let's consider the second one an integer...) the second *and*
the first parameter (...oh, but then we have to promote the first one to a
string).
The BCL is not setting the priority here as much as VB.NET itself is setting
the priority here. Based on the rules that I gave links to earlier.

VB.NET is not assuming the second is an integer, the literal 1 is defined to
be an integer. As clearly stated in the following topic:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbls7/html/vblrfvbspec2_4_2.asp

Hence your sample is effectively:

Const c As Char = "C"c
Const i As Integer = 1

Dim test1 As New Something(c, i)

Seeing as the Integer cannot be squeezed into a Byte, while the Char can be
expanded into a String, the String/Integer overload is the one that is used!

Hope this helps
Jay


Klaus Löffelmann said:
That

Why would I say that? The overloading resolution works fine, here, it's
unquestionable.
I just wanted to say, that to my mind the BCL sets the priority wrong in the
given example. The Integer/byte decision is not clear, granted. But actually
there is no mistake about char. All I said was that I'd rather stick to the
obvious (Char is clear, let's have the second parameter a byte then)
than
 

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