Righteous Wrath Online Community

General => Lobby => Topic started by: Thorin on September 23, 2008, 04:05:39 PM

Title: VB.NET and Short-Circuiting
Post by: Thorin on September 23, 2008, 04:05:39 PM
VB6 programmers know full-well that VB6 did not have short-circuiting.  That is, in an If statement all conditions were examined.  This meant that the following would cause an error:

Set x = Nothing
If Not x Is Nothing And x.y = 10 Then
End If

The error being that after determining that x is Nothing, VB6 would still try to compare x's y property to 10.  This, of course, is not possible, as x is Nothing and therefore has no properties.

Along comes VB.NET, where they proudly proclaim to have added short-circuiting!

So I write that same code

If Not x Is Nothing And x.y = 10 Then
End If

Sure enough, an exception is thrown!  Why?  Because in their infinite wisdom, the developers of VB.NET added new keywords to use for short-circuiting.  You see, old VB6 programmers might get confused by the new behaviour of the keyword "And", as that keyword used to do both bitwise and logical operations (how @%&#ed is that?!).  So here's the code you're supposed to use in VB.NET if you want to short-circuit:

If Not x Is Nothing AndAlso x.y = 10 Then
End If

Here's the blog where I found out the truth: http://www.panopticoncentral.net/articles/919.aspx.
Title: Re: VB.NET and Short-Circuiting
Post by: Mr. Analog on September 23, 2008, 04:21:20 PM
This is one of the many reasons why I prefer C# and took my learning in that direction way back when. There are kludgy things like this in VB.NET to bridge the differences between VB6 and MSIL concepts.

Heck even in Java doing something like this:

if (blah != null && blah.equalsIgnoreCase("Hello World")){
       doSomething();
}


Took a little bit of getting used to (well, after working heavily with scripting languages which don't support this kind of statement gracefully). So I can see how it would be frustrating.

(modified by, you know, finishing my half-thought...)
Title: Re: VB.NET and Short-Circuiting
Post by: Darren Dirt on September 25, 2008, 11:24:56 AM
Quote from: Thorin on September 23, 2008, 04:05:39 PM
Along comes VB.NET, where they proudly proclaim to have added short-circuiting!

So I write that same code

If Not x Is Nothing And x.y = 10 Then
End If

Sure enough, an exception is thrown!  Why?  Because in their infinite wisdom, the developers of VB.NET added new keywords to use for short-circuiting.  You see, old VB6 programmers might get confused by the new behaviour of the keyword "And", as that keyword used to do both bitwise and logical operations (how @%&#ed is that?!).  So here's the code you're supposed to use in VB.NET if you want to short-circuit:

If Not x Is Nothing AndAlso x.y = 10 Then
End If

Here's the blog where I found out the truth: http://www.panopticoncentral.net/articles/919.aspx.


http://en.wikipedia.org/wiki/Short-circuit_evaluation

http://en.wikipedia.org/wiki/Comparison_of_C_Sharp_and_Visual_Basic_.NET#Equality_and_other_comparison_operators

WOW though -- I rely on that kinda shorthand ("short-circuiting") ALL the time in Javascript, since it makes the code way ... um... shorter.
Title: Re: VB.NET and Short-Circuiting
Post by: Thorin on September 25, 2008, 11:54:27 AM
Yeah, a lot of non-VB programmers rely on short-circuiting.  What's weird is a lot of old VB programmers used to rely on non-short-circuiting to call methods from their if statements even when the first test in the if statement was already false.  For instance:

Dim x As Integer
Dim y As Integer
x = -1
If x = 1 And y = GetValue() Then
    MsgBox(x)
Else
    MsgBox(y)
End If

Yet, a C#, C++, C, Java, or JavaScript programmer would shake their head at this, thinking that y is never set to a value so it should bork.
Title: Re: VB.NET and Short-Circuiting
Post by: Mr. Analog on September 25, 2008, 01:01:41 PM
Actually I seem to recall a lot of short circuiting assertions in C++, it makes debugging hell if it doesn't work properly but I know I've seen lots of

if (x = this.getThatThing() || x = this.getThatOtherThing())

If I ever caught a programmer writing this I'd use the Board of "Education" on 'em
Title: Re: VB.NET and Short-Circuiting
Post by: Thorin on September 25, 2008, 02:01:06 PM
Quote from: Mr. Analog on September 25, 2008, 01:01:41 PM
Actually I seem to recall a lot of short circuiting assertions in C++, it makes debugging hell if it doesn't work properly but I know I've seen lots of

if (x = this.getThatThing() || x = this.getThatOtherThing())

If I ever caught a programmer writing this I'd use the Board of "Education" on 'em

I concur, that's an excellent example of what not to do.  Thanks to short-circuiting, x would hold the return from getThatThing() unless getThatThing() didn't return anything, in which case x would hold the return from getThatOtherThing().

But hey, as soon as I see a single equals sign in an if statement, I'm suspicious - if statements are not the right place to make assignments!  (unfortunately I work with VB now, where the single equals sign is both assignment and comparison operator)
Title: Re: VB.NET and Short-Circuiting
Post by: Mr. Analog on September 25, 2008, 02:54:18 PM
Anytime I see "clever" code I take a second look ;)
Title: Re: VB.NET and Short-Circuiting
Post by: Tom on September 25, 2008, 03:56:04 PM
Quote from: Mr. Analog on September 25, 2008, 02:54:18 PM
Anytime I see "clever" code I take a second look ;)
Yeah, theres not often a good reason for clever code. sometimes, but not often.

I tend to code things in small simple layers that build on one another, where each layer is simple enough not to need anything too clever.
Title: Re: VB.NET and Short-Circuiting
Post by: Darren Dirt on September 25, 2008, 04:54:15 PM
Quote from: Thorin on September 25, 2008, 02:01:06 PM
Quote from: Mr. Analog on September 25, 2008, 01:01:41 PM
Actually I seem to recall a lot of short circuiting assertions in C++, it makes debugging hell if it doesn't work properly but I know I've seen lots of

if (x = this.getThatThing() || x = this.getThatOtherThing())

If I ever caught a programmer writing this I'd use the Board of "Education" on 'em

I concur, that's an excellent example of what not to do.  Thanks to short-circuiting, x would hold the return from getThatThing() unless getThatThing() didn't return anything, in which case x would hold the return from getThatOtherThing().

Actually... wouldn't x hold the return from getThatThing() but then THAT would be "OR"ed with the return from getThatOtherThing() -- whether or not the first call worked as expected or not?

Ugh.

Maybe the intention was more like:
if (x = this.getThatThing()){do_this()}
else if(x = this.getThatOtherThing()){do_that()}


(in other words, forgetting that Call1 || Call2 means "Call1, or Call2, OR call BOTH") ? ...okay now my brain hurts...



Title: Re: VB.NET and Short-Circuiting
Post by: Tom on September 25, 2008, 05:07:04 PM
Quote from: Darren Dirt on September 25, 2008, 04:54:15 PM
Quote from: Thorin on September 25, 2008, 02:01:06 PM
Quote from: Mr. Analog on September 25, 2008, 01:01:41 PM
Actually I seem to recall a lot of short circuiting assertions in C++, it makes debugging hell if it doesn't work properly but I know I've seen lots of

if (x = this.getThatThing() || x = this.getThatOtherThing())

If I ever caught a programmer writing this I'd use the Board of "Education" on 'em

I concur, that's an excellent example of what not to do.  Thanks to short-circuiting, x would hold the return from getThatThing() unless getThatThing() didn't return anything, in which case x would hold the return from getThatOtherThing().

Actually... wouldn't x hold the return from getThatThing() but then THAT would be "OR"ed with the return from getThatOtherThing() -- whether or not the first call worked as expected or not?

Ugh.

Maybe the intention was more like:
if (x = this.getThatThing()){do_this()}
else if(x = this.getThatOtherThing()){do_that()}


(in other words, forgetting that Call1 || Call2 means "Call1, or Call2, OR call BOTH") ? ...okay now my brain hurts...

No. = binds tighter than ||. = always evaluates first, on both sides.

Here's the C++ operator precedence table: http://www.cppreference.com/wiki/operator_precedence
Title: Re: VB.NET and Short-Circuiting
Post by: Lazybones on September 25, 2008, 05:24:57 PM
DEPENDING on tricks and precedence to push out one or two lines less code is evil. I think code should be written in such a way that someone that does not know that language could figure out basically what it does just by looking at it (with in reason).
Title: Re: VB.NET and Short-Circuiting
Post by: Thorin on September 25, 2008, 06:02:25 PM
Quote from: Darren Dirt on September 25, 2008, 04:54:15 PM
Quote from: Thorin on September 25, 2008, 02:01:06 PM
Quote from: Mr. Analog on September 25, 2008, 01:01:41 PM
Actually I seem to recall a lot of short circuiting assertions in C++, it makes debugging hell if it doesn't work properly but I know I've seen lots of

if (x = this.getThatThing() || x = this.getThatOtherThing())

If I ever caught a programmer writing this I'd use the Board of "Education" on 'em

I concur, that's an excellent example of what not to do.  Thanks to short-circuiting, x would hold the return from getThatThing() unless getThatThing() didn't return anything, in which case x would hold the return from getThatOtherThing().

Actually... wouldn't x hold the return from getThatThing() but then THAT would be "OR"ed with the return from getThatOtherThing() -- whether or not the first call worked as expected or not?

Ugh.

Maybe the intention was more like:
if (x = this.getThatThing()){do_this()}
else if(x = this.getThatOtherThing()){do_that()}


(in other words, forgetting that Call1 || Call2 means "Call1, or Call2, OR call BOTH") ? ...okay now my brain hurts...

In the example that Mr. Analog gave, the return value from this.getThatThing() is being assigned into the variable x.  Because this is happening as part of the test portion of an if statement, the test becomes whether the assignment worked correctly or not independent of the data or lack of data in x.  In an ORed statement like that, with short-circuiting, as soon as the first part of the test returns true the rest gets skipped.  Thus, x will hold the return value from this.getThatThing(), unless the assignment of the return value into x didn't succeed.  And then if that assignment didn't work, then the second part of the if statement is run so x will hold the return value from this.getThatOtherThing(), and the if statement will still enter the True branch as long as the second assignment works.

The absolute @%&#ed part about all that is that you enter the true branch so long as the assignment to x worked.

So, to recap what happens in the example:

1. this.getThatThing() gets run, and it's return value gets assigned to x
2. if x was assigned to properly(*), this.getThatOtherThing() is skipped and the true branch of the if statement is run
3. if x was not assigned to properly, this.getThatOtherThing() gets run, and it's return value gets assigned to x
4. if x was assigned to properly(*), the true branch of the if statement is run
5. if x was not assigned to properly, the false branch of the if statement is run

(*) Pretty much the only ways the assignment won't work is if there's a type conversion error, like if getThatThing() returns a string and x is an integer variable, or if your machine just ran out of memory (in which case everything's borked anyway)
Title: Re: VB.NET and Short-Circuiting
Post by: Tom on September 25, 2008, 07:36:11 PM
QuoteBecause this is happening as part of the test portion of an if statement, the test becomes whether the assignment worked correctly or not independent of the data or lack of data in x.
In C/C++ and Perl, the foo=bar statement resolves to the final value of foo, since = doesn't return a boolean if it succeeded or failed. So in those languages you can indeed test for the final value.
Title: Re: VB.NET and Short-Circuiting
Post by: Thorin on September 26, 2008, 01:06:36 AM
Quote from: Tom on September 25, 2008, 07:36:11 PM
QuoteBecause this is happening as part of the test portion of an if statement, the test becomes whether the assignment worked correctly or not independent of the data or lack of data in x.
In C/C++ and Perl, the foo=bar statement resolves to the final value of foo, since = doesn't return a boolean if it succeeded or failed. So in those languages you can indeed test for the final value.

Well, based on the coding convention used I'd say the example was intended to be seen as Java code.

However, I remember writing C++ code way back in CST, and if you only put one equals sign the return value from the function you called was assigned to the variable and you *always* hit the true branch.  The only way to get the false branch to run was to cause the called function to return something that the variable couldn't hold without an explicit cast.  In fact, I remember spending several hours banging my head against the wall (so to speak) because I'd missed one equals sign and was too tired to notice it and couldn't figure out why the false branch of my if construct was never reached!
Title: Re: VB.NET and Short-Circuiting
Post by: Darren Dirt on September 26, 2008, 02:24:09 PM
Quote from: Thorin on September 26, 2008, 01:06:36 AM
Quote from: Tom on September 25, 2008, 07:36:11 PM
QuoteBecause this is happening as part of the test portion of an if statement, the test becomes whether the assignment worked correctly or not independent of the data or lack of data in x.
In C/C++ and Perl, the foo=bar statement resolves to the final value of foo, since = doesn't return a boolean if it succeeded or failed. So in those languages you can indeed test for the final value.

Well, based on the coding convention used I'd say the example was intended to be seen as Java code.

However, I remember writing C++ code way back in CST, and if you only put one equals sign the return value from the function you called was assigned to the variable and you *always* hit the true branch.  The only way to get the false branch to run was to cause the called function to return something that the variable couldn't hold without an explicit cast.

^ Winner of the "Clear Post Of The Day" award.

I think now we all agree on what all of us were trying to say ;D  Thanks!
Title: Re: VB.NET and Short-Circuiting
Post by: Mr. Analog on September 26, 2008, 03:13:35 PM
Quote from: Darren Dirt on September 26, 2008, 02:24:09 PM
Quote from: Thorin on September 26, 2008, 01:06:36 AM
Quote from: Tom on September 25, 2008, 07:36:11 PM
QuoteBecause this is happening as part of the test portion of an if statement, the test becomes whether the assignment worked correctly or not independent of the data or lack of data in x.
In C/C++ and Perl, the foo=bar statement resolves to the final value of foo, since = doesn't return a boolean if it succeeded or failed. So in those languages you can indeed test for the final value.

Well, based on the coding convention used I'd say the example was intended to be seen as Java code.

However, I remember writing C++ code way back in CST, and if you only put one equals sign the return value from the function you called was assigned to the variable and you *always* hit the true branch.  The only way to get the false branch to run was to cause the called function to return something that the variable couldn't hold without an explicit cast.

^ Winner of the "Clear Post Of The Day" award.

I think now we all agree on what all of us were trying to say ;D  Thanks!

Sick thing is that it all makes sense to most of use here...

You know what my other favourite line of code to see nested three or four times?


//Seriously I will beat you if you do this all the time
dont = (x != y) ? everdo : this.kindaCode;

//NOOOOOOOOOOOOO!!!!
blah = (x == ((a > b) ? true : false) ? y : z;
Title: Re: VB.NET and Short-Circuiting
Post by: Thorin on September 26, 2008, 03:48:42 PM
Ahh, ternary operators.  Yes, always a good idea to write really cryptic code with those!  I love when they're nested four or five deep, and indentation isn't properly followed so the poor maintenance programmer has to re-arrange the code before it makes sense.
Title: Re: VB.NET and Short-Circuiting
Post by: Darren Dirt on September 26, 2008, 04:49:48 PM
Quote from: Thorin on September 26, 2008, 03:48:42 PM
Ahh, ternary operators.  Yes, always a good idea to write really cryptic code with those!  I love when they're nested four or five deep, and indentation isn't properly followed so the poor maintenance programmer has to re-arrange the code before it makes sense.

I luvs teh ternary -- especially within bookmarklets and the like... All hail the ternary! Heathen unbelievers of the ternary, enjoy your lengthy scrolling code, I live by teh ternary.
Title: Re: VB.NET and Short-Circuiting
Post by: Tom on September 26, 2008, 05:01:20 PM
Know what I like even more than the ternary operator?

computed gotos. Its GCC only so don't expect it to work on MSVC or anything:


#define NEXT ({ int *ptr = NULL; int next_op = fetch_op(); ptr = table + next_op; goto **ptr; })
void *table = { &&LABEL1, && LABEL2, ... };
LABEL1:
  do_something();
  NEXT;

LABEL2:
  do_somethingelse();
  NEXT;


And why would I do something so evil? Its about ten times faster than this:
do {
   switch(op) {
      case LABEL1:
         do_something();
         break;
       case LABEL2:
          do_somethingelse();
          break;
   }
} while(!end);


:)
Title: Re: VB.NET and Short-Circuiting
Post by: Mr. Analog on April 21, 2009, 10:33:53 PM
Quote from: Tom on September 26, 2008, 05:01:20 PM
Know what I like even more than the ternary operator?

computed gotos. Its GCC only so don't expect it to work on MSVC or anything:


#define NEXT ({ int *ptr = NULL; int next_op = fetch_op(); ptr = table + next_op; goto **ptr; })
void *table = { &&LABEL1, && LABEL2, ... };
LABEL1:
  do_something();
  NEXT;

LABEL2:
  do_somethingelse();
  NEXT;


And why would I do something so evil? Its about ten times faster than this:
do {
   switch(op) {
      case LABEL1:
         do_something();
         break;
       case LABEL2:
          do_somethingelse();
          break;
   }
} while(!end);


:)

Not to single you out, but I just noticed a HUGE no-no which would net you a ding in a code review (if I were doing it).

Where's your default on your switch? I see a lot of programmers make this mistake because "op" will always be LABEL1 or LABEL2... y'know, except when we add LABEL3 after about a year.

Draconian maybe, but realistic... ;)

I should post my (C#) Coding Standards doc its got a lot of goodies in it.

For example: In the .NET Framework why would you want to make a private constructor on an object that has no member data?

I'm thinking most of you get it, but I'm surprised how many people came back and asked me about it when I wrote my draft doc.
Title: Re: VB.NET and Short-Circuiting
Post by: Tom on April 22, 2009, 10:10:59 PM
Quote from: Mr. Analog on April 21, 2009, 10:33:53 PM
Quote from: Tom on September 26, 2008, 05:01:20 PM
Know what I like even more than the ternary operator?

computed gotos. Its GCC only so don't expect it to work on MSVC or anything:


#define NEXT ({ int *ptr = NULL; int next_op = fetch_op(); ptr = table + next_op; goto **ptr; })
void *table = { &&LABEL1, && LABEL2, ... };
LABEL1:
  do_something();
  NEXT;

LABEL2:
  do_somethingelse();
  NEXT;


And why would I do something so evil? Its about ten times faster than this:
do {
   switch(op) {
      case LABEL1:
         do_something();
         break;
       case LABEL2:
          do_somethingelse();
          break;
   }
} while(!end);


:)

Not to single you out, but I just noticed a HUGE no-no which would net you a ding in a code review (if I were doing it).

Where's your default on your switch? I see a lot of programmers make this mistake because "op" will always be LABEL1 or LABEL2... y'know, except when we add LABEL3 after about a year.

Draconian maybe, but realistic... ;)

I should post my (C#) Coding Standards doc its got a lot of goodies in it.

For example: In the .NET Framework why would you want to make a private constructor on an object that has no member data?

I'm thinking most of you get it, but I'm surprised how many people came back and asked me about it when I wrote my draft doc.
It was an example ;) IIRC my real code has a default, which jumps to error handling code. But the loop-switch exec loop isn't even enabled by default in that project. Its too slow.

The fun part about the computed goto is that if the opcode is horribly wrong, bad things will happen ;D and not just "falling out of the switch" bad, but "app crashing" bad. So its something you have to be very careful with. If it were run on win9x, and the opcode was wrong, it could crash the entire OS by jumping to some random memory address in the system and doing all kinds of horrible things.
Title: Re: VB.NET and Short-Circuiting
Post by: Mr. Analog on April 23, 2009, 12:37:49 AM
Quote from: Tom on April 22, 2009, 10:10:59 PM
Quote from: Mr. Analog on April 21, 2009, 10:33:53 PM
Quote from: Tom on September 26, 2008, 05:01:20 PM
Know what I like even more than the ternary operator?

computed gotos. Its GCC only so don't expect it to work on MSVC or anything:


#define NEXT ({ int *ptr = NULL; int next_op = fetch_op(); ptr = table + next_op; goto **ptr; })
void *table = { &&LABEL1, && LABEL2, ... };
LABEL1:
  do_something();
  NEXT;

LABEL2:
  do_somethingelse();
  NEXT;


And why would I do something so evil? Its about ten times faster than this:
do {
   switch(op) {
      case LABEL1:
         do_something();
         break;
       case LABEL2:
          do_somethingelse();
          break;
   }
} while(!end);


:)

Not to single you out, but I just noticed a HUGE no-no which would net you a ding in a code review (if I were doing it).

Where's your default on your switch? I see a lot of programmers make this mistake because "op" will always be LABEL1 or LABEL2... y'know, except when we add LABEL3 after about a year.

Draconian maybe, but realistic... ;)

I should post my (C#) Coding Standards doc its got a lot of goodies in it.

For example: In the .NET Framework why would you want to make a private constructor on an object that has no member data?

I'm thinking most of you get it, but I'm surprised how many people came back and asked me about it when I wrote my draft doc.
It was an example ;) IIRC my real code has a default, which jumps to error handling code. But the loop-switch exec loop isn't even enabled by default in that project. Its too slow.

The fun part about the computed goto is that if the opcode is horribly wrong, bad things will happen ;D and not just "falling out of the switch" bad, but "app crashing" bad. So its something you have to be very careful with. If it were run on win9x, and the opcode was wrong, it could crash the entire OS by jumping to some random memory address in the system and doing all kinds of horrible things.

Well, that's good to hear, some people honestly don't "get it" and will blindly assume that because something is a struct or an enum that it is written in stone and incorruptible.