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"?
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.