VB.NET chops the Ouroboros in half! Critical hit! The Ouroboros takes 0 damage!



  • So... I was working on some ASP.NET VB code and I was wondering why when I clicked the link button with ID "lbGoalTask_83", I was getting an error saying that there was no such record... yes, I did click on the right link button, but for some reason I wasn't geting the 83 out of the ID - when I went into the database, record 83 was definitely there! I was about at the point of asking my boss to come and take a look at my code, when I noticed this line:

    Dim dgtID As Integer = dgtID = lb.ID.Split("_")(1)

    Looks pretty innocuous right? Wait... why does dgtID appear TWICE??? I guess I typed it in once as a Dim statement and once as a regular assignment... but how could it possibly be doing what it's doing (setting dgtID to zero)? In order to assign dgtID, it would first need to compare the existing value of dgtID to the link button ID, but in order to do THAT, it would need a value of dgtID to compare, but dgtID is not declared yet, which should cause a compile error...

    I wonder what happens with this code:

    Dim dgtID As Integer = dgtID = 0

    Would it set dgtID to zero (the second equals sign being an assignment), or to one (the second equals sign being a comparison)?

    Now, C#, I bet C# would throw a compiler error in equivalent scenarios!



    1. Get a mod to fix the topic. It's not relevant and too long.
    2. C# does not throw an error. IL throws an error because the evaluation stack is empty.
    3. Too wise you aren't. Just as this isn't 4chan, this isn't Mensa for 3rd graders.
    4. Yeah, that's a WTF. It's your WTF. Fix it and quit blaming the compiler.
    Thanks.


  • @TwelveBaud said:

  • Get a mod to fix the topic. It's not relevant and too long.
  • C# does not throw an error. IL throws an error because the evaluation stack is empty.
  • Too wise you aren't. Just as this isn't 4chan, this isn't Mensa for 3rd graders.
  • Yeah, that's a WTF. It's your WTF. Fix it and quit blaming the compiler.
    1. The topic is fine, this is the sidebar, it doesn't have to be relavent, just memorable.
    2. Why wasn't he getting any errors then?
    3. What does that even mean?
    4. He knows its his mistake, he openly admitted to that.  The WTF is that not a single warning was raised about the flawed syntax. 


  • @ekolis said:

    In order to assign dgtID, it would first need to compare the existing value of dgtID to the link button ID, but in order to do THAT, it would need a value of dgtID to compare, but dgtID is not declared yet, which should cause a compile error...

    Last time I checked, BASIC was not C, and didn't require you to pre-declare variables.



  • @Carnildo said:

    @ekolis said:
    In order to assign dgtID, it would first need to compare the existing value of dgtID to the link button ID, but in order to do THAT, it would need a value of dgtID to compare, but dgtID is not declared yet, which should cause a compile error...

    Last time I checked, BASIC was not C, and didn't require you to pre-declare variables.

     

    Last time I checked, VB.NET was not BASIC, and did require you to pre-declare variables.



  •  I'm still curios, and despite how little coding knowledge i have, setting something as itsalf should cause an error.



  • @Carnildo said:

    @ekolis said:
    In order to assign dgtID, it would first need to compare the existing value of dgtID to the link button ID, but in order to do THAT, it would need a value of dgtID to compare, but dgtID is not declared yet, which should cause a compile error...

    Last time I checked, BASIC was not C, and didn't require you to pre-declare variables.

    C lets you do it too: 

    /tmp/wtf $ cat ouroboros.c
    #include <stdio.h>

    int foo (void)
    {
      int fooval = fooval = 3;
      return fooval;
    }

    int main (int argc, const char **argv)
    {
      int barval = barval = 0;
      printf ("fooval is %d\n", foo ());
      return barval;
    }
    /tmp/wtf $ gcc-4 -g -O2 -W -Wall -Wuninitialized -Wextra ouroboros.c -o ouroboros
    ouroboros.c: In function 'main':
    ouroboros.c:9: warning: unused parameter 'argc'
    ouroboros.c:9: warning: unused parameter 'argv'
    /tmp/wtf $ ./ouroboros.exe ; echo $?
    fooval is 3
    0
    /tmp/wtf $



  • @Steeldragon said:

     I'm still curios, and despite how little coding knowledge i have, setting something as itsalf should cause an error.

     

    It's because the meaning of the equals ("=") sign in Visual Basic changes depending on the context; it acts as both an assignment operator and a boolean comparison operator. At least, I think that's the root cause of the OP's problem, unless I'm completely misreading his post. It's interpreting "dgtID = lb.ID.Split("_")(1)" as a boolean comparison, and taking the result of that comparison and assigning it to dgtID. Using similar syntax in C# (say, "int dgtID = dgtID = lb.ID.Split("_")(1)") will result in assigning the correct value to the same variable twice (which most likely will be optimized out of the assembly anyway).



  • There wasn't an error raised because it is a legal statement.

    It compiles down to this...

    Dim dgtID as Integer

    dgtID = dgtID = lb.ID.Split("_")(1)

     

    The first = is an assignment, the second = is a comparison.  VB has always worked like this.  Since dgtID does not equal lb.ID.Split("_")(1) it returns false which becomes 0 when converted to an integer.



  • @durendal.mk3 said:

    It's because the meaning of the equals ("=") sign in Visual Basic changes depending on the context; it acts as both an assignment operator and a boolean comparison operator.

    Yeah, that's what it is.  Outside an if block, the first equals is the assignment and all subsequent operators are treated as comparisons.



  • @KattMan said:

    Since dgtID does not equal lb.ID.Split("_")(1) it returns false which becomes 0 when converted to an integer.

    Question: does VB.NET initialize all uninitialized variables to 0, like the BASIC I grew up with, or does it leave it whatever happened to reside in that memory block, like C? I'd hope that it would do the former, but, as a previous poster pointed out, VB.NET <> BASIC.



  • @tgape said:

    @KattMan said:
    Since dgtID does not equal lb.ID.Split("_")(1) it returns false which becomes 0 when converted to an integer.

    Question: does VB.NET initialize all uninitialized variables to 0, like the BASIC I grew up with, or does it leave it whatever happened to reside in that memory block, like C? I'd hope that it would do the former, but, as a previous poster pointed out, VB.NET <> BASIC.

     

    Like any OOP/Garbage collected language I know objects get null and primitives get their default value (well in .NET primitives do not actually exists, but structs get their default value too)



  • @DaveK said:

    @Carnildo said:

    @ekolis said:
    In order to assign dgtID, it would first need to compare the existing value of dgtID to the link button ID, but in order to do THAT, it would need a value of dgtID to compare, but dgtID is not declared yet, which should cause a compile error...

    Last time I checked, BASIC was not C, and didn't require you to pre-declare variables.

    C lets you do it too: 

    /tmp/wtf $ cat ouroboros.c
    #include <stdio.h>

    int foo (void)
    {
      int fooval = fooval = 3;
      return fooval;
    }

    int main (int argc, const char **argv)
    {
      int barval = barval = 0;
      printf ("fooval is %d\n", foo ());
      return barval;
    }
    /tmp/wtf $ gcc-4 -g -O2 -W -Wall -Wuninitialized -Wextra ouroboros.c -o ouroboros
    ouroboros.c: In function 'main':
    ouroboros.c:9: warning: unused parameter 'argc'
    ouroboros.c:9: warning: unused parameter 'argv'
    /tmp/wtf $ ./ouroboros.exe ; echo $?
    fooval is 3
    0
    /tmp/wtf $

    Actually, the C program is working in the right way, and the OPs code would work as advertised if VB acted like C.

    TRWTF is that VB uses the same operator for two different operations: assignment and comparison, while most languages use different operators (like = and == or := and =). This WTF shows how easily someone can screw up with this.

    Oh, by the way:

    VB.NET = VB6 + real OO and C#/Project Cool's "I didn't copy Java" features.

    VB6,5,4,whatever = QuickBasic + graphical interface (and support for sensible variable names)

    QuickBasic = BASIC + Function and Sub support.

    So VB.NET might be something like BASIC's grandchild.



  • @danixdefcon5 said:

    @DaveK said:

    @Carnildo said:

    @ekolis said:
    In order to assign dgtID, it would first need to compare the existing value of dgtID to the link button ID, but in order to do THAT, it would need a value of dgtID to compare, but dgtID is not declared yet, which should cause a compile error...

    Last time I checked, BASIC was not C, and didn't require you to pre-declare variables.

    C lets you do it too: 

    /tmp/wtf $ cat ouroboros.c
    #include <stdio.h>

    int foo (void)
    {
      int fooval = fooval = 3;
      return fooval;
    }

    int main (int argc, const char **argv)
    {
      int barval = barval = 0;
      printf ("fooval is %d\n", foo ());
      return barval;
    }
    /tmp/wtf $ gcc-4 -g -O2 -W -Wall -Wuninitialized -Wextra ouroboros.c -o ouroboros
    ouroboros.c: In function 'main':
    ouroboros.c:9: warning: unused parameter 'argc'
    ouroboros.c:9: warning: unused parameter 'argv'
    /tmp/wtf $ ./ouroboros.exe ; echo $?
    fooval is 3
    0
    /tmp/wtf $

    Actually, the C program is working in the right way, and the OPs code would work as advertised if VB acted like C.

    TRWTF is that VB uses the same operator for two different operations: assignment and comparison, while most languages use different operators (like = and == or := and =). This WTF shows how easily someone can screw up with this.

    Heh, yeh, I was cheating a bit because the C doesn't mean quite the same as the VB.  As I see it, there are two sides to this wtf: first, that you can use the name of a variable when you're still in the course of declaring it, which is surprising to anyone who discovers it for the first time, then second that you can apparently use an uninitialised value without getting a warning - which happens for a different reason, in VB because the value isn't uninitialised, in C because it's being assigned-to rather than compared.

    @danixdefcon5 said:

    Oh, by the way:

    VB.NET = VB6 + real OO and C#/Project Cool's "I didn't copy Java" features.

    VB6,5,4,whatever = QuickBasic + graphical interface (and support for sensible variable names)

    QuickBasic = BASIC + Function and Sub support.

    So VB.NET might be something like BASIC's grandchild.

    I think VB.NET has the same relationship to BASIC as Daleks do to Kaleds: it's not so much a grandchild as the mutant bastard offspring of a million years' artificially forced evolution in a toxic radioactive hell hole.  And I'm being nice about it because I'm in a good mood today.



  • OK, there is a very fundamental principle that is at work here, and it seems that it is not widely understood.

    In BASIC (and variants of), there are two types of construct that are used to write programs: Statements and Expressions

    A Statement is a command for the computer to do something. Statements can take a number of Arguments. Generally speaking each argument is an Expression. Statements do things, but do not have a value.

    An Expression is something that has a value. This may be a simple value such as "3" or it may be made up of a combination of Operators and other Expressions, such as "1 + 2" or "SQRT(3+LEN(A$))". Some Expressions may be functions and as such they may cause things to happen in a Statement-like way, but they are not Statements because they have values. Expressions cannot generally be used "on thier own" in BASIC, they must be an Argument of a Statement.

    In C (and C++ etc.) there is no such thing as a Statement - everything is a function, and therefore an Expression.

    In BASIC the message "Hello World" can be displayed using the PRINT Statement:

    PRINT "Hello World"

    This is a Statement that takes a single Expression and displays it - there is no "return value".

    In C the message "Hello World" can be displayed using the printf function:

    printf("Hello World\n");

    This is really just an Expression that is made up of a function taking a single argument. Evaluating the expression causes the function to be called and this displays the message. However, the key think to know here is that unlike the PRINT Statement in BASIC, the message display is technically a side-effect of calculating the value of the function. In this case the value is 12, and it is discarded.

    In C the Expression "LValue = Expr" has a value of Expression "Expr" and a side-effect of setting "LValue" to that value. The Expression could validly be another instance of this assignment Expression. So "a = b = c;" is broken down into "a = (b = c)", then "b = c" is processed, setting b to the value of c and returning the value of c. Next "a = c" is processed, as the value of "(b + c)" was discovered to be "c". End result, all three variable end up with the same value.

    In early versions of BASIC there was a Statement "LET Variable = Expr" that set the value of Expression "Expr" into "Variable". Later versions of BASIC made the "LET" keyword optional (in fact more modern versions may not even have this keyword). If you get BASIC to process "LET A = B = C" it will see that this is a LET statement with "Variable" equal to "A" and "Expr" equal to "B = C". The first "=" is part of the syntax of the LET statement, the second is an Expression operator. So, first "B = C" will be evaluated by comparing the two values, this will give 0 if they are different and a non-zero value if they are the same (what value depends on which version of BASIC!). The result of this boolean comparison is then set into "A".

    When a modern version of BASIC sees "A = B = C" it needs to first find the statement, and the only way to find one here is to insert the optional "LET".

    </BoringLecture>



  • @ekolis said:

    Now, C#, I bet C# would throw a compiler error in equivalent scenarios!

     

     No. In C# (and I would assume VB.NET too) int (Integer) is a value type.

    Which means a struct. Which means it's already initialized to 0 from the point you declare it.

     There you go.



  • @GettinSadda said:

    In C (and C++ etc.) there is no such thing as a Statement - everything is a
    function, and therefore an Expression.

    That is preposterous.

    C has the following types of statements:

    • compound statement ( { ... } );
    • expression statement (expression + ;);
    • null statement (;);
    • selection statements: if and switch;
    • iteration statements: while, do and for;
    • jump statements: goto, continue, break and return.

    There is also a notion of a labeled statement, but that's just a special case of one of the above. C++ adds declaration statements and try blocks.

    On the other hand, these are the statements the latest VB has:

    • label declaration statement (which is kind of special, but listed for completeness);
    • local declaration statement;
    • With statement;
    • SyncLock statement;
    • event statements: RaiseEvent, AddHandler and RemoveHandler;
    • assignment statements: regular, compound and Mid;
    • invocation statement;
    • conditional statements: If and Select Case;
    • loop statements: While, Do, For and For Each;
    • exception-handling statements: structured (Try and Throw) and unstructured (Error, On Error and Resume);
    • branch statements: GoTo, Exit, Continue, Stop, End and Return;
    • array handling statements: ReDim and Erase;
    • Using statement;

    But there is no expression statement. That's why there is no ambiguity between the regular assignment statement and a certain comparison operator which may occur in an expression.

    OT: Markdown is awesome.



  • @AngelSL said:

    @ekolis said:

    Now, C#, I bet C# would throw a compiler error in equivalent scenarios!

     

     No. In C# (and I would assume VB.NET too) int (Integer) is a value type.

    Which means a struct. Which means it's already initialized to 0 from the point you declare it.

     There you go.

     

    no it doesn't.  try and compile this:

    int a;

    int b;

    b = a;



  • @Spectre said:

    @GettinSadda said:
    In C (and C++ etc.) there is no such thing as a Statement - everything is a function, and therefore an Expression.

    That is preposterous.

    C has the following types of statements:

    ...

    Yeah - OK, but I was trying to simplify. Languages are much more complicated tham most people think - but even the basic principles are not always well understood.

    I think I shall refrain from attempting to clarify things in future as someone always picks holes in any attempt to do that.

     



  • @Spectre said:

    @GettinSadda said:
    In C (and C++ etc.) there is no such thing as a Statement - everything is a function, and therefore an Expression.

    That is preposterous.

    C has the following types of statements:

    • compound statement ( { ... } );
    • expression statement (expression + ;);
    • null statement (;);
    • selection statements: if and switch;
    • iteration statements: while, do and for;
    • jump statements: goto, continue, break and return.

    There is also a notion of a labeled statement, but that's just a special case of one of the above. C++ adds declaration statements and try blocks.

    On the other hand, these are the statements the latest VB has:

    • label declaration statement (which is kind of special, but listed for completeness);
    • local declaration statement;
    • With statement;
    • SyncLock statement;
    • event statements: RaiseEvent, AddHandler and RemoveHandler;
    • assignment statements: regular, compound and Mid;
    • invocation statement;
    • conditional statements: If and Select Case;
    • loop statements: While, Do, For and For Each;
    • exception-handling statements: structured (Try and Throw) and unstructured (Error, On Error and Resume);
    • branch statements: GoTo, Exit, Continue, Stop, End and Return;
    • array handling statements: ReDim and Erase;
    • Using statement;

    But there is no expression statement. That's why there is no ambiguity between the regular assignment statement and a certain comparison operator which may occur in an expression.

    OT: Markdown is awesome.

     

    Actually, if you're getting technical, if(), while(), switch(), for(), and do() are all functions.

    And even if C used the same symbol for assignment and evaluation,  int c = c = some_value; would still be legal because c would be initialized to stack trash.  In any language, the addition of the variable to the symbol table occurs before the assignment is parsed;  C++ has assignment constructors, of course, but that doesn't change the rule--only what happens as a result of the parsing. 

    On further reflection I can see that holding in a single-pass compiler or interpreter.  In a multi-pass compiler or interpreter, I can see that being held in abeyance.  Javascript comes to mind.



  • @mrprogguy said:

    Actually, if you're getting technical, if(), while(), switch(), for(), and do() are all functions.

    And even if C used the same symbol for assignment and evaluation,  int c = c = some_value; would still be legal because c would be initialized to stack trash.  In any language, the addition of the variable to the symbol table occurs before the assignment is parsed;  C++ has assignment constructors, of course, but that doesn't change the rule--only what happens as a result of the parsing. 

    On further reflection I can see that holding in a single-pass compiler or interpreter.  In a multi-pass compiler or interpreter, I can see that being held in abeyance.  Javascript comes to mind.

    Are you missing TopCod3r or something?

Log in to reply