I noticed that the parameter a evaluates to diff in the watch window (even if b is non-zero), when breaking on the return statement line, which doesn't make sense to me. If uncommenting the line above, that doesn't happen. Any ideas? Do you guys get the same result? I used Visual Studio Ultimate 2013 12.0.40629.00 Update 5, debug build.
public decimal Subtract(decimal a, decimal b)
{
var diff = a - b;
//var test = a;
return diff;
}
since this is probably a compiler issue
Depends on your definition of "issue". What you see is not unexpected if you are debugging an optimized build. The C# compiler is unlikely to coalesce variable storage (I'm guessing it simply can't), but the JIT compiler, which is what creates the native code that actually executes, certainly can and most likely would.
So, your variable a, being unused after the assignment to diff, is having its storage location reused for the variable diff, rather than allocating a whole new location for it.
Since both variables are using the same location, when you watch the value in the debugger, changing one variable has the effect of changing the other.
For more discussion on debugging optimized builds, see:
Cannot obtain value because it has been optimized away
What is the point of nop in CIL
The second link doesn't really pertain to the "reused variable slot" aspect per se, but Hans' answer does include the sentence "You can still debug a Release build, it is however a pretty confounding experience that makes you doubt your sanity", which IMHO sums up the whole broad topic nicely. :)
Related
I have a simple class intended to store scaled integral values
using member variables "scaled_value" (long) with a "scale_factor".
I have a constructor that fills a new class instance with a decimal
value (although I think the value type is irrelevant).
Assignment to the "scaled_value" slot appears... to not happen.
I've inserted an explicit assignment of the constant 1 to it.
The Debug.Assert below fails... and scaled_value is zero.
On the assertion break in the immediate window I can inspect/set using assignment/inspect "scale_factor"; it changes as I set it.
I can inspect "scaled_value". It is always zero. I can type an
assignment to it which the immediate window executes, but its value
doesn't change.
I'm using Visual Studio 2017 with C# 2017.
What is magic about this slot?
public class ScaledLong : Base // handles scaled-by-power-of-ten long numbers
// intended to support equivalent of fast decimal arithmetic while hiding scale factors from user
{
public long scaled_value; // up to log10_MaxLong digits of decimal precision
public sbyte scale_factor; // power of ten representing location of decimal point range -21..+21. Set by constructor AND NEVER CHANGED.
public byte byte_size; // holds size of value in underlying memory array
string format_string;
<other constructors with same arguments except last value type>
public ScaledLong(sbyte sf, byte size, string format, decimal initial_value)
{
scale_factor = sf;
byte_size = size;
format_string = format;
decimal temp;
sbyte exponent;
{ // rip exponent out of decimal value leaving behind an integer;
_decimal_structure.value = initial_value;
exponent = (sbyte)_decimal_structure.Exponent;
_decimal_structure.Exponent = 0; // now decimal value is integral
temp = _decimal_structure.value;
}
sbyte sfDelta = (sbyte)(sf - exponent);
if (sfDelta >= 0)
{ // sfDelta > 0
this.scaled_value = 1;
Debug.Assert(scaled_value == 1);
scaled_value = (long)Math.Truncate(temp * DecimalTenToPower[sfDelta]);
}
else
{
temp = Math.Truncate(temp / DecimalHalfTenToPower[-sfDelta]);
temp += (temp % 2); /// this can overflow for value at very top of range, not worth fixing; note: this works for both + and- numbers (?)
scaled_value = (long)(temp / 2); // final result
}
}
The biggest puzzles often have the stupidest foundations. This one is a lesson in unintended side effects.
I found this by thinking about, wondering how in earth a member can get modified in unexpected ways. I found the solution before I read #mjwills comment, but he was definitely sniffing at the right thing.
What I left out (of course!) was that I had just coded a ToString() method for the class... that wasn't debugged. Why did I leave it out? Because it obviously can't affect anything so it can't be part of the problem.
Bzzzzt! it used the member variable as a scratchpad and zeroed it (there's the side effect); that was obviously unintended.
When this means is that when code the just runs, ToString() isn't called and the member variable DOES get modified correctly. (I even had unit tests for the "Set" routine checked all that and they were working).
But, when you are debugging.... the debugger can (and did in this case) show local variables. To do that, it will apparently call ToString() to get a nice displayable value. So the act of single stepping caused ToSTring() to get called, and its buggy scratch variable assignment zeroed out the slot after each step call.
So it wasn't a setter that bit me. It was arguably a getter. (Where is FORTRAN's PURE keyword when you need it?)
Einstein hated spooky actions at a distance. Programmers hate spooky side effects at a distance.
One wonders a bit at the idea of the debugger calling ToString() on a class, whose constructor hasn't finished. What assertions about the state of the class can ToString trust, given the constructor isn't done? I think the MS debugger should be fixed. With that, I would have spent my time debugging ToString instead of chasing this.
Thanks for putting up with my question. It got me to the answer.
If you still have a copy of that old/buggy code it would be interesting to try to build it under VS 2019 and Rider (hopefully the latest, 2022.1.1 at this point) with ReSharper (built in) allowed to do the picky scan and with a .ruleset allowed to bitch about just about anything (just for the 1st build - you'll turn off a lot but you need it to scream in order to see what to turn off). And with .NET 5.0 or 6.0
The reason I mention is that I remember some MS bragging about doing dataflow analysis to some degree in 2019 and I did see Rider complaining about some "unsafe assignments". If the old code is long lost - never mind.
CTOR-wise, if CTOR hasn't finished yet, we all know that the object "doesn't exist" yet and has invalid state, but to circumvent that, C# uses default values for everything. When you see code with constant assignments at the point of definition of data members that look trivial and pointless - the reason for that is that a lot of people do remember C++ and don't trust implicit defaults - just in case :-)
There is a 2-phase/round initialization sequence with 2 CTOR-s and implicit initializations in-between. Not widely documented (so that people with weak hearts don't use it :-) but completely deterministic and thread-safe (hidden fuses everywhere). Just for the sake of it's stability you never-ever want to have a call to any method before the 2 round is done (plain CTOR done still doesn't mean fully constructed object and any method invocation from the outside may trigger the 2nd round prematurely).
1st (plain) CTOR can be used in implicit initializations before the 2nd runs => you can control the (implicit) ordering, just have to be careful and step through it in debugger.
Oh and .ToString normally shouldn't be defined at all - on purpose :-) It's de-facto intrinsic => compiler can take it's liberties with it. Plus, if you define it, pretty soon you'll be obliged to support (and process) format specifiers.
I used to define ToJson (before big libs came to fore) to provide, let's say a controllable printable (which can also go over the wire and is 10-100 times faster than deserialization). These days VS debugger has a collection of "visualizers" and an option to tell debugger to use it or not (when it's off then it will jerk ToString's chain if it sees it.
Also, it's good to have dotPeek (or actual Reflector, owned by Redgate these days) with "find source code" turned off. Then you see the real generated code which is sometimes glorious (String is intrinsic and compiler goes a few extra miles to optimize its operations) and sometimes ugly (async/await - total faker, inefficient and flat out dangerous - how do you say "deadlock" in C# :-) - not kidding) but you need to to be able to see the final code or you are driving blind.
This is very dangerous so I wonder why it's allowed. Since I often need to switch between VB.NET and C# I sometimes add breakpoint-conditions like following:
foo = "bah"
I want to stop if the string variable foo is "bah, so the correct way was to use foo == "bah" instead of foo = "bah".
But it "works". You don't get any warnings or errors at compile- or runtime. But actually this modifies the variable foo, it makes it always "bah" even if it had a different value. Since that happens silently (the breakpoint never gets hit) it is incredibly dangerous.
Why is it allowed? Where is my error in reasoning (apart from confusing the C# and VB.NET syntax)? In C# (as opposed to VB.NET) an assignment statement returns the value that was assigned, so not a bool, but a string in this case. But a breakpoint condition has to be a bool if you check the box "Is True".
Here is a little sample "program" and screenshots from my (german) IDE:
static void Main()
{
string foo = "foo";
// breakpoint with assignment(foo = "bah") instead of comparison(foo == "bah"):
Console.WriteLine(foo); // bah, variable is changed from the breakpoint window
}
The breakpoint-condition dialog:
The code as image including the breakpoint:
It is an automatic consequence of C# syntax, common in the curly-braces language group. An assignment is also an expression, its result is the value of the right-hand side operand. The debugger does not object either to expressions having side-effects, nor would it be simple at all to suppress them. It could be blamed for not checking that the expression has a bool result, the debugger however does not have a full-blown C# language parser. This might well be fixed in VS2015 thanks to the Roslyn project. [Note: see addendum at the bottom].
Also the core reason that the curly-brace languages need a separate operator for equality, == vs =. Which in itself must be responsible for a billion dollar worth of bugs, every C programmer makes that mistake at least once.
VB.NET is different, assignment is a statement and the = token is valid for both assignment and comparison. You can tell from the debugger, it picks the equality operator instead and doesn't modify the variable.
Do keep in mind that this is actually useful. It lets you temporarily work around a bug, forcing the variable value and allowing you to continue debugging and focus on another problem. Or create a test condition. That's pretty useful. In a previous life-time, I wrote a compiler and debugger and implemented "trace points". Discovered the same scenario by accident and left it in place. It ran in a host that relied heavily on state machines, overriding the state variable while debugging was incredibly useful. The accident, no, not so useful :)
A note about what other SO users are observing, it depends on the debugging engine that you use. The relevant option in VS2013 is Tools + Options, Debugging, General, "Use Managed Compatibility Mode" checkbox. Same option exists in VS2012, it had a slightly different name (don't remember). When ticked you get an older debugging engine, one that is still compatible with C++/CLI. Same one as used in VS2010.
So that's a workaround for VS2013, untick the option to get the debugger to check that the expression produces a bool result. You get some more goodies with that new debugging engine, like seeing method return values and Edit+Continue support for 64-bit processes.
I can disagree about buggy nature of this behavior. Few examples where for debugging purposes in my life if was useful:
1. Other thread modifies something in your code.
2. Other service updated value in db
So I suppose for cases of synchronization it can be useful feature, but I agree that it can cause problems
In Visual Studio 2019, variable assignment expressions in Breakpoint conditions no longer work.
The expression will be evaluated for value, but side effects such as variable assignment are discarded.
https://developercommunity.visualstudio.com/content/problem/715716/variables-cannot-be-assigned-in-breakpoint-conditi.html
(edit: b is an existing boolean)
Is
b = (a > c);
faster than
if (a > c)
b = true;
in general ?
and considering the fact that in my case (a > c) is false most of the time ?
edit : I know gains will very small even though this part of code will be executed a large number of times. But I'm still intereste in theoretical answer.
Thank you
As Darin says, you should use whatever's more readable to you the speed difference if any will be insignificant... but it's worth noting that they're not equivalent. If this is within a method (so b is a local variable) then the first approach will leave b definitely assigned, whereas the second won't.
Personally I'd just use:
bool b = a > c;
I don't think there's any need for extra brackets, and I prefer to initialize at the point of declaration. If I did use an if block, I'd definitely use braces...
Talking about faster here doesn't make sense in practice as this is a micro optimization that you shouldn't be doing. As far as which one of the two you should be using, use the one that's more readable to you (the first seems more readable to me).
The second one is completely useless. The variable isn't definitely assigned afterwards. So you can't read it and need to assign it again before it is used, which overwrites the result of your assignment.
But I wouldn't worry about such micro optimizations unless really necessary. And in that case you need to profile and inspect the generated assembly code anyways.
AFAIK an optimization similar to this makes sense if you assign to a reference type field(not local variable). Since assignments of reference fields have some additional cost related to interaction with the GC. But with local variables I except no significant difference. The assignment might be slightly faster in some cases, since conditionals problematic if the branch prediction fails.
Apart from the error as mentioned in the other answers, in a managed language like C#, there is absolutely no use in these kind of optimizations. There are so many layers of translations before this code actually gets evaluated. Optimizations like these only make sense if you're in Assembly or Ye Olde C++.
Well, the second version, will take more memory (if we don't consider optimizations etc) on the hard drive - i.e the file will be larger.
The first goes like this:
store a > b in x
mov b,x
The second one will go like this:
store a > b in x
is x true?
Yes:
b = true
continue execution
No:
continue execution
I have created the following functions in C#:
float GetPI()
{
return 22.0f/7.0f;
}
void Calculate()
{
float f1 = GetPI()*4;
float f2 = GetPI()*5;
}
If I create a release build, how will I be able to verify whether the JIT compiler will cache the 22/7 calculation, or whether it will be calculated each time the function GetPI is called?
PS : I do not have visual C# studio professional edition
EDIT : changed 22/7 to 22.0f/7.0f to make the example function more accurate
I'm not sure what you mean by being cached. Unless the compiler doesn't do any constant folding (which it will in this case) or the runtime doesn't inline your function (which it probably would in this case), it will not do any "caching" automatically for you.
The expression 22f/7f is a constant expression and can be evaluated at compile time (aka, constant folding). So in the compiled assembly, it will appear as:
float GetPI()
{
return 3.142857f; // however many digits of precision
}
The compiler will always make this kind of optimization if given the opportunity. Unless there's a compiler option to disable this (which I'm not sure there is). To verify this happens, you could use Reflector (as the others have pointed out) to see the compiled assembly. You should see that it does indeed do this whether it is Debug or Release builds or using the express versions (unless this optimization is explicitly disabled).
If the function is simple enough, the runtime might inline your function call. So rather than calling this function, it will insert the result in place of the function call. Seeing as this is just a function to just return some number, it will probably will do this optimization. I don't know if there even is a way to see if this happens without actually seeing the JIT compiled code through a debugger.
If you mean caching as in memoization, then no this will not be done automatically and you'll have to do this yourself.
If you want an absolute guarantee that the compiler will "cache" (as in not recalculate the quotient) the value, you should declare your value as a constant (or use the existing and more accurate System.Math.PI constant). Nothing is being determined at runtime, everything is known at compile time. And every time you use this value, it will be "inlined" so you won't have to worry about that.
const float PI = 22f / 7f; // will be stored as 3.142857f
// or another way, if you need PI to be a float but want a more accurate value
const float PI = (float)Math.PI; // will store as much precision possible
// note that this only works because Math.PI is declared as a constant
Download and install .NET Reflector (originally written by Lutz Roeder, and now maintained by Red Gate). You may have to look for an older version if you don't want to pay.
When you open your code in Reflector, you can see what changes the compiler made.
This wouldn't show you JIT optimizations, you need to step through the machine code in a debugger for that, but I'm pretty sure this case will be evaluated by the C# compiler.
There are many ways. One convenient is using .NET Reflector.
Open up your assembly in Reflector, select C#, find the method in the treeview, select Tools/Disassemble. The disassembler will show something like the following:
public float GetPI()
{
return 3f;
}
We have some unit tests that fail when run in Release mode vs debug mode. If I attach a debugger in release mode the tests pass. There is way too much code to publish here so I am really just looking for best practices in debugging Release mode issues. I have checked for:
DEBUG and RELEASE preprocessor directives but I did not find any.
Conditional Methods
SOLUTION: In this case it is because I was comparing floating point variables for equality. I could not change the floats to decimal without a major refactoring so I added an extension method:
public static class FloatExtension
{
public static bool AlmostEquals(this float f1, float f2, float precision)
{
return (Math.Abs(f1 - f2) <= precision);
}
public static bool AlmostEquals(this float f1, float f2)
{
return AlmostEquals(f1, f2, .00001f);
}
public static bool AlmostEquals(this float? f1, float? f2)
{
if (f1.HasValue && f2.HasValue)
{
return AlmostEquals(f1.Value, f2.Value);
}
else if (f1 == null && f2 == null)
{
return true;
}
return false;
}
}
One thing that might cause the behaviour that you are seeing is an error that causes a race condition. Attaching a debugger can change the timing of the code such that the race condition is no longer triggered.
To fix it, use synchronization appropriately whenever you have multiple threads accessing data.
I am comparing some float values in the IsEqual method.
That sounds like a very bad idea. You should not compare floats for equality because floating point calcualtions are not 100% precise and you can get representation and rounding errors. Compare to see whether they are sufficiently close together. For calculations involving money, you probably want to use the decimal type instead.
Since it seems to be floating point related there are so many things that can go wrong. See:
C# - Inconsistent math operation result on 32-bit and 64-bit
and
Double precision problems on .NET
There are so many things that can be trashed with floating points. And comparing floats for equality is a general no-no. You chould check the difference smaller than a reasonably epsilon.
Questions you should ask yourself -
Is my code threaded? Timing differences will affect output
Is someone calling Debug.Assert() with an expression that side effects?
What objects implement IDisposable() and do some do so in such a way that changes state?
Are you P/Invoking into unmanaged code?
Number 3 is a very likely bad-boy in this case. Garbage collection may be very different in debug and release and you may find that when an object is garbage collected is affecting the outcome of a later unit test.
And FYI, if you're using NUnit and TestDriven.NET - the two run tests in different orders.
This is often the case as the debug build is not optimized by default, and even if you enable it, the behavior when debugging is very different. You can disable the "Optimize code" from the project settings for all assemblies on the Properties->Build tab.
There are certainly other changes that can cause differences, like you mention Conditional Methods are one. These I've found to rarely be the cause of issues, for me it's almost always the optimizer.
Classic gotcha's of the optimizer include methods that get 'inlined' so that they fail to appear on a call stack. This causes problems when using System.Diagnostics.StackFrame classes to determine the current execution point. Similarly this will affect the result of MethodBase.GetCurrentMethod or other functions/behavior that rely on the executing method.
Then there are of course many things I've seen the optimizer do that I simply cannot explain at all. One such example was documented and discussed in a post 'HashDerivedBytes - replacing Rfc2898DeriveBytes, but why?' but I've never solved the mystery. I only know that the optimizer just flat broke Rfc2898DeriveBytes when used to generate a series of derived bytes. Oddly enough this only broke when the bytes generated were not evenly divisible by the size of the hash algorithm used (20) and only produced incorrect results after the first 20 bytes.
The fact is that optimizations adversely affecting code is not a new thing for compilers. Most of the old-school C++ developers will tell you that straight away and then, as I did, go into some long drawn out story about how they worked around it ;)
As Mark suggests, this is usually a result of a timing-related issue, often a race condition or synchronization problem.
One common way to handle this sort of problem is to use "print" statements in the affected areas to show you what's going on. If the print statements (Console.WriteLine, Response.Write, logging, or whatever) make the problem go away, store the values in global variables and print the globals once the problem has shown up.
The most recent time this has happened to me was in code that was reading from a serial port. The debugging activity caused just enough of a change in timing to affect how bytes from the serial port were buffered, which changed how the buffer was getting parsed. Since the print statements changed the timing, I had to store the data up to output later.
Just to add my two cents to this, I recently found that I had a date comparison in an sql procedure that the testing called. The dates were all auto-generated prior in the test procedure and values were inserted into the DB, and so occasionally they were exactly the same (when using RunTests) causing a null to be returned on a table join. Not what I was expecting. Obviously, in debug mode, since I'm slowly progressing through it, there will be a difference in the auto-generated times which meant that I never bumped into the error. I resolved this by inserting
Threading.Thread.Sleep(520)
wherever there would definitely be a delay between actions. Problem fixed.