62

I wrote a program that allow two classes to "fight". For whatever reason C# always wins. What's wrong with VB.NET ?

   static void Main(string[] args)
    {
        Player a = new A();
        Player b = new B();

        if (a.Power > b.Power)
            Console.WriteLine("C# won");
        else if (a.Power < b.Power)
            Console.WriteLine("VB won");
        else
            Console.WriteLine("Tie");
    }

Here are the players: Player A in C#:

public class A : Player
{
    private int desiredPower = 100;

    public override int GetPower
    {
        get { return desiredPower; }
    }
}

Player B in VB.NET:

Public Class B
   Inherits Player

   Dim desiredPower As Integer = 100

   Public Overrides ReadOnly Property GetPower() As Integer
       Get
          Return desiredPower
       End Get
   End Property
 End Class

And here is a base class.

public abstract class Player
{
    public int Power { get; private set; }

    public abstract int GetPower { get; }

    protected Player()
    {
        Power = GetPower;
    }
}
Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Prankster
  • 4,031
  • 5
  • 33
  • 44
  • Try writing each "power" to the console as well. – Joel Coehoorn Apr 02 '09 at 20:59
  • 5
    Hot damn, you must tell me your secret to finding all of these quirks with C#. – Samuel Apr 02 '09 at 21:02
  • I don't understand the close votes. This is an interesting question with no clear answer yet. – mqp Apr 02 '09 at 21:09
  • 1
    This is where I want to be able to cast an anti-close vote. – Ray Apr 02 '09 at 21:09
  • They might be a reaction to the crazy confusing code. – recursive Apr 02 '09 at 21:09
  • As I suspected. Looks like VB.Net is calling the Base constructor before the inherited constructor, and therefore VB's desiredPower variable is still 0, whereas C# does it in reverse (remember, literal initialization happens at the end of the constructor). – Joel Coehoorn Apr 02 '09 at 21:09
  • 4
    So if people can't understand code in a question... they *close* the question. That seems counter to the mission of Stack Overflow. It does appear the constructor application order matters, and frankly *I* didn't know that and found this informative. – Godeke Apr 02 '09 at 21:12
  • This close reason makes no sense at all. It's a concrete question about a concrete code sample. How did this get five votes to close? What's going on here? – mqp Apr 02 '09 at 21:12
  • Same here. Voted to re open. – recursive Apr 02 '09 at 21:12
  • Can you report voting abuse? There is no way this should have even gotten one close vote. – Samuel Apr 02 '09 at 21:13
  • I think an administrator stepped in, because it was briefly closed, and now all the close votes have vanished. – mqp Apr 02 '09 at 21:13
  • Um, where are the implementations for Power() ? – JeffH Apr 02 '09 at 21:15
  • Maybe it was closed by hyper-sensitive VB programmers who don't like any suggestion (even a tongue in cheek one) that their language is inferior to C#? – 1800 INFORMATION Apr 02 '09 at 21:16
  • @Jeff - the implementation for Power is in the Player base class – 1800 INFORMATION Apr 02 '09 at 21:16
  • "public int Power { get; private set; }" implements the getter and setter implicitly. – Godeke Apr 02 '09 at 21:16
  • @1800 - I think I'm missing something - I don't see an assignment or return in get/set for Power - How does Power know anything about the member variable? – JeffH Apr 02 '09 at 21:20
  • Power doesn't know anything about it. It gets initialized in the constructor using the GetPower virtual method. – mqp Apr 02 '09 at 21:22
  • @JeffH - see the comment by Godeke - it is implemented implicitly, I think this was a new feature in .Net 3.0 – 1800 INFORMATION Apr 02 '09 at 21:24
  • Perhaps voting should be changed to require reputation if it overruled. The fact this even got one vote is ridiculous. – Samuel Apr 02 '09 at 21:28
  • I'll tell you why I voted to close -- because this was presented as if there was something "wrong" with VB instead of asking why the code didn't work as expected. Clearly VB handles the initialization of member variables differently, but that doesn't make it "wrong." – tvanfosson Apr 02 '09 at 21:30
  • IMO that made the question "argumentative." In fact, I felt that it wasn't really a valid question at all since I felt the person was simply trying to denigrate VB. Note that I'm a C# programmer by trade so it has nothing to do with my feelings being hurt. – tvanfosson Apr 02 '09 at 21:31
  • Aha! - I didn't know about automatic properties. Once I did google.com/search?q="private+set"+vb.net I was set straight. @1800, @mquander, @Godeke THANKS. – JeffH Apr 02 '09 at 21:34
  • I strongly disagree that it was presented that way, and I don't believe that would be a good reason to close it if it were. If you didn't feel it was a valid question, you should have continued on and read the very specific and objective question he outlined in his post. – mqp Apr 02 '09 at 21:35
  • The OP took a little creativity to his question, but if you spent more than 10 seconds reading it, you could have easily seen that is it nowhere near argumentative or subjective. – Samuel Apr 02 '09 at 21:35
  • @tvanfosson: tThat may be true... if you read the title only. Read the question and it was pretty clear that your assumption was way off. – Neil N Apr 02 '09 at 21:36
  • you shouldnt vote to close a topic on its title alone. – Neil N Apr 02 '09 at 21:37
  • @mquander -- the ONLY question in his post is "what's wrong with VB.NET?" The rest is merely code. @Samuel -- if the only question I asked of you was "what's wrong with Samuel?" you might feel a little put upon. – tvanfosson Apr 02 '09 at 21:40
  • @tvan: And that code tells a story, a story of his misconception that the order of base ctors being called. And I would say that not a fair analogy, to him the behaviour of VB.Net is "wrong" when compared to C#. – Samuel Apr 02 '09 at 21:46
  • @tvanfosson: Take it easy. The wording may be a little sloppy but still this is an interesting question. I don't think there is anything wrong with a little provocative style. In general I would wish for more tolerance on SO because closing question is annoying to many people. – Dirk Vollmar Apr 02 '09 at 22:05
  • I guess the stakes must be pretty low since my little close vote has caused so much grief. “Academic politics is the most vicious and bitter form of politics, because the stakes are so low” Wallace Sayre – tvanfosson Apr 02 '09 at 22:10
  • well, don't get offended by something as benign as "What's wrong with VB.NET?" And we can avoid such situations in the future. – Neil N Apr 02 '09 at 22:30
  • 3
    I opened the question expecting to be offended, but then I *read* it. First it made me laugh, then it made me think. Nice work. – MarkJ Apr 04 '09 at 10:23

4 Answers4

45

The issue here is that VB is calling the base constructor before setting its field value. So the base Player class stores zero.

.method public specialname rtspecialname 
        instance void  .ctor() cil managed
{
  // Code size       15 (0xf)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [base]Player::.ctor()
  IL_0006:  ldarg.0
  IL_0007:  ldc.i4.s   100
  IL_0009:  stfld      int32 B::desiredPower
  IL_000e:  ret
} // end of method B::.ctor
Jb Evain
  • 17,319
  • 2
  • 67
  • 67
16

Promoting my comments to an answer:

Me:

Try writing each "power" to the console as well

Prankster:

C#: 100 VB.NET: 0

Me:

As I suspected. Looks like VB.Net is calling the Base constructor before the inherited constructor, and therefore VB's desiredPower variable is still 0, whereas C# does it in reverse (remember, literal initialization happens at the end of the constructor).

Update:
I wanted to find some documentation on the behavior (otherwise you're looking at behavior that might change out from under you with any new .Net release). From the link:

The constructor of the derived class implicitly calls the constructor for the base class

and

Base class objects are always constructed before any deriving class. Thus the constructor for the base class is executed before the constructor of the derived class.

Those are on the same page and would seem to be mutually exclusive, but I take it to mean the derived class constructor is invoked first, but it is assumed to itself invoke the base constructor before doing any other work. Therefore it's not constructor order that important, but the manner in which literals are initialized.

I also found this reference, which clearly says that the order is derived instance fields, then base constructor, then derived constructor.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
1

This happens because C# first initialize class fields, and than call base constructors. VB instead does the opposite, so when in VB you assign your value to Power, private field is not yet initialized and its value is 0.

Andrea Parodi
  • 5,534
  • 27
  • 46
1

By the time the constructor on B completes, both players will have a theoretical value of 100 in their private members.

However because of the superior internals of C#, the CLI generally considers integers and other primitive values values compiled from that language to be higher, and those from VB.NET to be lower, even when they contain the same bits.

James Orr
  • 5,005
  • 7
  • 39
  • 63