3

I was decompiling an open-source project (because the source for the latest version hasn't been released yet). Using RedGate's Reflector tool, it gave me this block of code:

if(somecondition == true)
{
    ref Vector3i vectoriRef;
    float num17 = length - num;
    Vector3i end = vectori3;
    (vectoriRef = (Vector3i) &end)[1] = vectoriRef[1] - ((int) num17);
}

somecondition is a boolean. length and num are floats defined outside the code. vectori3 is also defined outside the code and is of type Vector3i. The type Vector3i is essentially this code, but with x, y, and z stored as integers.

When I try to compile this decompiled code, I get the following errors:

  • Line 2: Only assignment, call, increment, decrement, and new object expressions can be used as a statement
  • Line 3: ; expected
  • Line 3: Invalid expression term 'ref'
  • Line 6: 'Vector3i' is a 'type' but is used like a 'variable'

Any thoughts on how I can fix this code so it compiles correctly and does whatever it was intended to do?

UPDATE: It turns out the source is available in their repository, but you have to follow a maze of links and clues to even find it. Thanks to everyone who posted!

Colin O'Dell
  • 8,386
  • 8
  • 38
  • 75

2 Answers2

4

The code uses a mutable value type, which is a "worst practice" in C#. The code that we generate for mutable value types can be quite difficult to correctly analyze and decompile; apparently you have run into a bug in the decompilation engine. C# does not support the given syntax. (It could in the future; I have written a prototype of "ref locals" and it works quite nicely, but it is not clear that the feature is actually valuable enough to customers to warrant a full design and implementation.)

Read the code carefully and you'll see what it is doing: it's making a copy of vectori3 into end, then obtaining a ref to end (remember, the "this" of a call to a value type is always a ref to a variable because the call might be mutating the contents of that variable.) Then its using the ref to mutate the variable. But why?? This code doesn't make any sense. Why would you make a local copy of a variable and then mutate the copy, and then discard the mutated copy?

I suspect that you've not only found a bug in the decompiler; you may have also found a bug in the code.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Immutable value types aren't a good practice either in some cases. I've shown here how immutable value types are not necesarily thread safe http://stackoverflow.com/questions/370859/why-isnan-is-a-static-method-on-the-double-class-instead-of-an-instance-property/370996#370996. But there's another side of the coin too, in XNA there's heavy use of mutable value types (Vectors, Matrices, etc.) due to performance reasons, and those datatypes were designed that way with the involvement of Rico Mariani, and he explained why (http://blogs.msdn.com/b/ricom/archive/2006/09/07/745085.aspx). – Pop Catalin Dec 24 '10 at 19:50
  • It's a worst practice to drive on a slipery road with 100 miles an hour? Well it depens, if you're trying to win a rally then it's not, otherwise it definatelly is. – Pop Catalin Dec 24 '10 at 19:51
  • 3
    @Pop: Your example of a "non threadsafe" immutable value type mutates a *variable*. Whether the *value type* is immutable or not is irrelevant; variables are by definition mutable. Furthermore, your example doesn't even *require* threading to illustrate that "this" can change in an immutable value type; **the threading is a red herring**. Code on the same thread, whether synchronous or asynchronous, could be changing the value of "this". Remember: **"this" is always a variable in a value type, and variables vary**. – Eric Lippert Dec 25 '10 at 01:20
  • 2
    @Pop: It is of course the case that sometimes a mutable value type is justified. But the practice is so dangerous and potentially confusing that the justification has to be really good. In the case of XNA, the choice to go with mutable vectors is clearly driven by carefully measured, real-world, user-scenario driven performance data. If you've got that kind of data to justify making a mutable value type, great, go for it, and document the heck out of that decision. If you don't, then avoid this 'worst practice' like the plague. – Eric Lippert Dec 25 '10 at 01:23
1

At first glance

if (somecondition)
{
    vectori3[1] -= (int)(length - num);
}

I'm not clear about the explicit reference syntax - I've never seen that before, and can't get VS to accept it - but the last line splits out into

vectoriRef = (Vector3i) &end;
vectoriRef[1] = vectoriRef[1] - ((int) num17);
Rup
  • 33,765
  • 9
  • 83
  • 112