5

Short version

How does the IF() function cause the passed expressions to NOT be evaluated prior to being passed in as parameters?

Detailed version

I am part of a standards committee, and a discussion was initiated which, in general, is trying to ban the use of the IIF() function. The general consensus is that if you want to do a short line-length assignment IF() is okay. And if you for some reason want to evaluate two expressions, don't try to accomplish that all on one line, explicitly and purposefully evaluate the expressions on seperate lines, then do an IF() call with the results in the If True and If Else parameters.

I'm asserting that before a Function(param1, expression) is stepped into, any expressions are evaluated. Then, their evaluated value is passed as a parameter.

That being asserted, this makes sense:

Sub Main()
    Dim intTest As Integer = 0
    Dim blnResult As Boolean = IIf(2 = 2, Integer.TryParse("3", intTest), Integer.TryParse("4", intTest))
    'intTest = 4
End Sub
  • As expected, blnResult is True.
  • Because the conditional of the IIF() function is True, the value of the expression in the "If True" parameter is the resulting assignment.
  • But BOTH the If True AND If Else expressions were evaluated (in written order) prior to even stepping into the IIF() function, so intTest became 4.
  • As far as I'm concerned, that is programatically expected, but not the results desired.

On the reverse side of the coin, we have this:

Sub Main()
    Dim intTest As Integer = 0
    Dim blnResult As Boolean = If(2 = 2, Integer.TryParse("3", intTest), Integer.TryParse("4", intTest))
    'intTest = 3
End Sub

As the inverse of the previous issue, we now have:

  • As expected, blnResult is True.
  • Because the conditional of the IF() function is True, the value of the expression in the "If True" parameter is the resulting assignment.
  • But ONLY the If True (in this case) is evaluated, so intTest became 3.
  • As far as I'm concerned, that is the results desired, but not programatically expected.

I'd like to see a custom function that does the same thing as IF().

  • 1
    Just verifying, the IFF(A,B,C) is equivalent to A?B:C in a C-esque language? – user40980 Aug 15 '13 at 21:18
  • 2
    IFF is a Mathematical functionality, not to be confused with VB.NET's IIF. But C-style: A?B:C, I believe, is more related to IF(A,B,C) in VB.NET, because if A is true, B is evaluated and assigned. Else, C is evaluated and assigned. But in C-esque, it makes more sense since that is procedural, whereas in VB.NET, it is a Function call, and that is the center of this question. – Suamere Aug 15 '13 at 21:20
  • 1
    I wouldn't be surprised if IF() wasn't a regular function but special in this regard, perhaps a keyword which just mandates parentheses to look like a function. This isn't an answer I have no idea how to verify my hypothesis. If this question is about VB.NET and not earlier versions, there may be an ECMA spec somewhere. – user7043 Aug 15 '13 at 22:07
  • @MichaelT Could you re-write your comment as the answer? That's exactly what happens in the Intermediate Language. I'm just sorry it took me that long to get to it. – Suamere Aug 16 '13 at 2:22
  • @Suamere I really don't know enough vb to be able to write a good answer (even if I did stumble on it) for this (or an environment to expand on how to explain it and the nuances of what it means). – user40980 Aug 16 '13 at 15:10
6

Your confusion stems from a misapprehension:

Inner Workings of the IF() Function

How does the IF() Function

the conditional of the IF() Function

I'd like to see a custom function that does the same thing as IF()

But IF() is not a function.

The language specification for VB.NET (freely available for download) has this to say about If. I quote the 11.0 version; emphases as mine, and note that the apparent error in the example is a direct quote!:

11.22 Conditional Expressions

A conditional If expression tests an expression and returns a value. Unlike the IIF runtime function, however, a conditional expression only evaluates its operands if necessary. Thus, for example, the expression If(c Is Nothing, c.Name, "Unknown") will not throw an exception if the value of c is Nothing.

Note the difference: If is an expression, whereas IIf is a function. Like any other function, IIf obeys the usual parameter evaluation rules. But If, being an expression, doesn't have to.

You wouldn't expect

If <condition> Then
    ' Do this
Else
    ' Do that
End If

to do both this and that; similarly, you shouldn't expect If to evaluate both parts.

You're not going to be able to readily make a function that does this, any more than you'd be able to (say) make a function that does what Using does - it's part of the language.

  • 1
    Seems to me like If(c Is Nothing, c.Name, "Unknown") should be the other way round. – flornquake Aug 16 '13 at 9:13
  • @flornquake good spot, have edited to note that this is a direct quote... – AakashM Aug 16 '13 at 9:30
  • @AakashM Thanks for the detail. IF() is indeed an expression and not a regular function. Though that was already said by some others, you added explination around it for those that would need it, could you put a link to that reference? – Suamere Aug 16 '13 at 15:05
  • BTW, not really a misapprehension. the Description of IF() in VS is: If TestExpression evaluates to True, the function calculates and returns the Truepart object. Otherwise, it returns the FalsePart object. But as my answer with the inner workings displays, the IL shows it as a C-Type Ternary Operation once the expression is broken down. Which we all know is how it works, but with that actual code, shows in reality exactly why behind the scenes. – Suamere Aug 16 '13 at 15:31
  • @Suamere from your answer and your comment it looks like you think CIL looks like C; it very much doesn't. If you are using Reflector or dotPeek or some other decompilation tool, they are for your convenience converting CIL into C# that produces that CIL. CIL actually looks like this. By the way, where are you quoting from there? – AakashM Aug 16 '13 at 15:34
3

IF() is treated as a special case by the compiler. You can't make your own function that works exactly the same way without making your own compiler. You could use delegates or lambda expressions to similar effect, though.

  • That obviously makes a lot of sense. Thanks. I'm hoping for something like this answer, but maybe for a reference for official reading on perhaps the general idea of things the compiler handles. Obviously along these lines, LINQ is included, but I'm hoping we don't have to live with what we think something is doing. Any references? I'm searching now. If I find it before anybody else I'll post it under this answer and mark it. – Suamere Aug 16 '13 at 1:49
  • 1
    @Suamere: Both C# and VB.NET come with language standards documents. I suspect that's going to be the only thing that satisfies your committee. – Robert Harvey Aug 16 '13 at 2:01
  • Thanks Robert! Microsoft's MSDN VB.Net Standards are certainly a consideration, as is also PlanetGeek. I came up with something though and am going to post it. – Suamere Aug 16 '13 at 2:12
3

You're basically describing short-circuit evaluation.

I don't see the issue you describe as fundamentally different than the difference between And and AndAlso. If you're going to ban IIF, you're also going to have to ban And, since it doesn't short-circuit either (both operands are always evaluated).

Banning language constructs that do not short circuit might make more sense if you also require your functions to never have side-effects. If you allow side effects in your functions, those side effects will not occur if they are in the short-circuited part of a function evaluation.

Further Reading
Why would a language NOT use Short-circuit evaluation?

  • Right, one of our standards are going to require Short-Circuit Evals only. I realize a conditional block using AndAlso is short-circuit evaluation, and +1 for your clarification on some of that, but I'm hoping for something like Karl's answer. – Suamere Aug 16 '13 at 1:48
  • What definition of "short-circuiting evaluation" are you using? The number of expressions evaluated by IF doesn't depend on the truth/falsehood of the first expression, no ? – user39685 Aug 16 '13 at 17:09
  • @MattFenwick: Call it whatever you wish to call it. I'm referring to the phenomenon of a function not being executed because the result of the boolean expression doesn't depend on the return value of the function. – Robert Harvey Aug 16 '13 at 17:10
  • I am confused by the first sentence of your comment. Why would I do that? I'd rather get to the correct answer at the bottom of this issue. I'm claiming the OP isn't about short-circuiting because of all the definitions I've seen of if statements, none of them ever mentioned short-circuiting, nor did they do something like short-circuiting because, as I've mentioned, the number of expressions (or branches if your ifs are like C's/Java's) evaluated is fixed, which is not the case with short-circuiting operators. And that is really the key point. Have I misunderstood something? – user39685 Aug 16 '13 at 18:07
  • 1
    @Matt: It says right in the documentation that "Visual Basic 2008 introduces a new If operator that uses short-circuit evaluation." Documentation for "IF" operator: Uses short-circuit evaluation to conditionally return one of two values. – Robert Harvey Aug 16 '13 at 18:09
1

VB.NET has an operator that does double duty as both the ternary and null coalescence operators. This operator is If. It also has a function, IIF, which takes three parameters.

These are two entirely different things. The IIF function is just that, a function, you could write your own that does the exact same thing. It should be avoided, it became obsolete the moment the operator was introduced.

Now, the IF operator is quite handy, and allows doing things that would have been extremely difficult to even approximate, and impossible to exactly duplicate, before lambdas were introduced (you still can't exactly duplicate it, but you could get a similar effect). There is no reason to avoid it, it behaves as expected, so even if you don't know about it, it doesn't surprise -- so it is not a danger for junior programmers.

Both functions of the If operator are basically short circuiting calculations, and that's a good thing.

If the standard you are working on is for using VB.NET, then it should be recommended. If it's for a new language, I recommend both operators as being useful additions to readable and understandable programs (you might want to make them a bit more distinct).

PS: You say that IIF behaves as expected, I would deny that and change your example a bit:

 Dim input as String = "Junior"
 Dim parsed as Integer
 parsed = IIF(IsNumeric(parsed), CInt(input), -1)

Throw that at someone not familiar with the language and they naturally expect parsed to be -1. Which is not what happens, instead you get an invalid cast exception. http://ideone.com/JfbFwi

I have fixed bugs exactly like the above.

0

Technical answer:

We all know the If() function is "the ternary operator for VB.NET", whereas IIF() is a function (though still technically ternary). But saying If() is "the ternary operator" doesn't mean we know what's going on behind the scenes. Well, it turns out literally what's going on behind the scenes is that the If() function is evaluated as an expression which is interpreted by Common Intermediate Language (CIL) as a C-esque ternary operator, as displayed in the CIL below:

bool arg_20_0 = true ? int.TryParse("3", out intTest) : int.TryParse("4", out intTest);

Description:

As part of the previous answers, it was brought up that the compiler probably interprets the IF() function as an expression instead of IF() actually being a regular function. It is partially true.

It was also brought up that if you were to ban IIF(), you'd also ban things like And and Or in place for short-circuit-only code. That was much closer to the real answer than I expected at first.

As a simple test, to which I am emberrassed I didn't try first, since I have ILSpy right on my desktop and use it all the time, I found that the real answer was the very first comment... MichaelT asked:

Just verifying, the IFF(A,B,C) is equivalent to A?B:C in a C-esque language?

LAWL!!! This is the CIL code:

bool arg_20_0 = true ? int.TryParse("3", out intTest) : int.TryParse("4", out intTest);

So it's partially true that IF() is not a real function, but it's evaluated in the CIL before going to the compiler, so it's not a function of creating your own compiler. I'll give credit to MichaelT if he posts this as his answer, he was 100% correct without even knowing it.

Edit (addition):

As stated in the comment, I said I'd post the CIL for IIF(). This is it...

bool blnResult = Conversions.ToBoolean(Interaction.IIf(true, int.TryParse("3", out intTest), int.TryParse("4", out intTest)));

Which is exactly as expected, because IIF is an actual function, so of course the parameters are evaluated before stepping into the function. I also sort of knew it was in the Interaction namespace. But like I said, IIF() isn't the mystery, it's understood, but just not the intended results.

  • I think you left off an I when you were compiling that -- it looks a lot like If not iIF... – jmoreno Aug 16 '13 at 3:58
  • Right, may have been confusion in the way I worded my question. The question is indeed How does IF() work. IIF actually works as expected, but has unintended results. IF() Works in unexpected ways, but has the intended results. So though IF() is better in the short-circuit sense, it is the one that is surrounded in mystery. Just for fun, though, I'll add the IL for IIF() to this answer. – Suamere Aug 16 '13 at 4:45
  • 2
    That is some very C#'ish looking IL... – Simon Whitehead Aug 16 '13 at 8:40
  • Never seen it any other way. That IL was compiled from the VB.Net Code: If(2 = 2, Integer.TryParse("3", intTest), Integer.TryParse("4", intTest)). As far as I know, all IL looks like C – Suamere Aug 16 '13 at 15:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.