Recently I moved from VB to C#, so I often use a C# to VB.NET converter to understand syntax differences. While moving next method to VB I noticed an interesting thing.
C# original code:
public bool ExceedsThreshold(int threshold, IEnumerable<bool> bools)
{
int trueCnt = 0;
foreach(bool b in bools)
if (b && (++trueCnt > threshold))
return true;
return false;
}
VB.NET result:
Public Function ExceedsThreshold(threshold As Integer, bools As IEnumerable(Of Boolean)) As Boolean
Dim trueCnt As Integer = 0
For Each b As Boolean In bools
If b AndAlso (System.Threading.Interlocked.Increment(trueCnt) > threshold) Then
Return True
End If
Next
Return False End Function
C#'s ++
operator replaced with System.Threading.Interlocked.Increment
Does it mean that not threadsafe ++
operator become threadsafe if used in foreach
loop? Is it a kind of syntax sugar? If that is true, then why converter placed Interlocked.Increment
in VB version? I thought foreach in both C# and VB works exactly the same. Or it's just a converter "insurance"?
It is used with a pointer variable pointing to a structure or union. The arrow operator is formed by using a minus sign, followed by the greater than symbol as shown below. Operation: The -> operator in C or C++ gives the value held by variable_name to structure or union variable pointer_name.
The not-equal-to operator ( != ) returns true if the operands don't have the same value; otherwise, it returns false .
I'm sure it's simply a converter hack, and I think I can explain the reasoning behind this.
But first, just to answer your question, the built-in ++
operator in C# is not thread-safe. It's simply a syntactic sugar for the following process (in the case of ++i
):
i
i
As there's a separate read and write, this is a non-atomic operation.
Now, in VB there is no direct equivalent of the ++
operator. The closest thing is:
i += 1
but this is a statement. By contrast, ++i
is an expression. You can use ++i
inside another statement or expression, but you can't do so with VB statements.
Using Interlocked.Increment
is only a clever way to translate the code easily, without having to break down the whole statement into multiple other statements.
Without this trick, the converter would have to break down the expression like this:
if (b && (++trueCnt > threshold))
...
If b Then
trueCnt += 1
If trueCnt > threshold Then
...
End If
End If
Which, as you can see, requires much more rewriting. It would even require introducing a separate temporary variable if trueCnt
were a property (to avoid evaluating it twice).
This requires a deeper semantic analysis and control flow rewriting than the simpler syntactic conversion your converter used - just because trueCnt += 1
can't be used inside an expression in VB.
I believe it's because you're wanting to increment the value in the same statement as doing the comparison. I don't have too much justification for that, but it sure feels like the right answer as trueCnt += 1 doesn't allow a comparison in the same line. It certainly has nothing to do with it being a foreach, try and add the same line outside the loop and I am almost certain it will convert to Increment also. There's simply no other syntax in VB .Net to both increment and compare in the same line.
In addition to the aforementioned issues, the default behavior of C# follows Java's unfortunate integer-overflow behavior. Although there are times when wrapping integer-overflow semantics are useful, C# generally makes no distinction between situations where integers should wrap on overflow versus those where integers aren't expected to wrap but the programmer doesn't think overflow trapping is worthwhile. This can muddle conversion efforts because VB.NET makes trapping behavior easier and faster than wrapping behavior, while C# does the reverse. Consequently, the logical way to translate code which uses unchecked math for reasons of speed would be to use ordinary checked math in VB.NET, while the logical way to translate code which needs wrapping behavior would be to use wrapping integer methods in VB.NET. The Threading.Interlocked.Increment
and Threading.Increment.Add
methods use wrapping integer behavior, so while they're not optimal from a speed perspective they are convenient.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With