tags:

views:

941

answers:

6

The question is in the title, why :

return double.IsNaN(0.6d) && double.IsNaN(x);

Instead of

return (0.6d).IsNaN && x.IsNaN;

I ask because when implementing custom structs that have a special value with the same meaning as NaN I tend to prefer the second.

Additionally the performance of the property is normally better as it avoid copying the struct on the stack to call the IsNaN static method (And as my property isn't virtual there is no risk of auto-boxing). Granted it isn't really an issue for built-in types as the JIT could optimize this easilly.

My best guess for now is that as you can't have both the property and the static method with the same name in the double class they favored the java-inspired syntax. (In fact you could have both as one define a get_IsNaN property getter and the other an IsNaN static method but it will be confusing in any .Net language supporting the property syntax)

+7  A: 

Interesting question; don't know the answer - but if it really bugs you, you could declare an extension method, but it would still use the stack etc.

static bool IsNaN(this double value)
{
    return double.IsNaN(value);
}

static void Main()
{
    double x = 123.4;
    bool isNan = x.IsNaN();
}

It would be nicer (for the syntax) if C# had extension properties, but the above is about the closest you can get at the moment, but it should "inline" quite well anyway.


Update; thinking about it, there is another difference between static and instance; C# always calls instance methods with "callvirt" rather than "call", even if ther type is sealed an non-nullable. So perhaps there is a performance benefit from having it static? Luckily, extension methods still count as static, so you get to retain this behavior.

Marc Gravell
Extension methods/properties haven't yet registered well in my head.. yet. Nice use.
Gishu
(note; I added a test rig which shows that it does indeed inline perfectly; the performance over 2,000,000,000 calls is within a few ms (either can be quicker, which is what we expect))
Marc Gravell
This general fluent extension instead of a static also has me creating a string.IsEmpty and string.IsNullOrEmpty as an instance
Ruben Bartelink
re the callvirt, as mentioned in other places, key diff between extension method and property is that in an extension you get to check if this == null, whereas the callvirt places a check for null and throw of NullReferenceException if it is.
Ruben Bartelink
@Mark the compiler never emits "callvirt" for methods on structures as it knows they can't be virtual ;) unless a "box" operand is emitted first.
Pop Catalin
@Pop - d'oh! You're right. I even loaded it into reflector to check, but I'm so "trained" to use class (rarely struct), that my fingers disobeyed me and wrote a class!
Marc Gravell
An instance method would box the primitive - thats the perf hit. maybe?
TheSoftwareJedi
@TheSoftwareJedi: boxing only occurs if "object" is involved. There is no need to box to call an instance method.
Marc Gravell
A: 

The distinction between an instance and a static is a fundamental point which the C# language (and Java as you say) chooses to make clear (in C++, you can call a static method through an instance, but thats just syntax - under the hood instance.StaticX is the same saying instance Class.StaticX.

The move towards fluent interfaces has started unravelling a lot of this though...

Ruben Bartelink
Yes Marc and sorry VBF, made a big botchjob on my initial response - didnt get the fact that you guys had that well covered and were considering things much more deeply than I was giving credit for! (My edits make you point less clear, but it definitely is correct - my bad!)
Ruben Bartelink
+11  A: 

Static Methods are thread safe, methods on primitives generally need to be thread safe to support threading in the platform (meaning at least safe from internal race conditions), instance methods take a managed pointer to a structure, meaning that the structure/primitive might be modified concurrently while the method executes, on the other hand static methods take a copy of the structure/primitive and therefore are safe from threading race conditions.

If the structure is intended to be thread safe, then the methods should be made instance methods only if they do atomic operations, else static methods should be chosen.

(As another option, instance methods that use locking could be used but they are more expensive than, copying)

Edit: @VirtualBlackFox I've prepared and example to show that instance methods on structures are not thread safe even on immutable structures:

using System;
using System.Threading;

namespace CA64213434234
{
    class Program 
    {
        static void Main(string[] args)
        {
            ManualResetEvent ev = new ManualResetEvent(false);
            Foo bar = new Foo(0);
            Action a =  () => bar.Display(ev);
            IAsyncResult ar = a.BeginInvoke(null, null);
            ev.WaitOne();
            bar = new Foo(5);
            ar.AsyncWaitHandle.WaitOne();
        }
    }

    public struct Foo
    {
        private readonly int val;
        public Foo(int value)
        {
            val = value;
        }
        public void Display(ManualResetEvent ev)
        {
            Console.WriteLine(val);
            ev.Set();
            Thread.Sleep(2000);
            Console.WriteLine(val);
        }
    }
}

The display Instance method prints: 0 5

even though the structure is immutable. For thread safe methods use static methods.

Pop Catalin
any citations to support this?
Ruben Bartelink
@Ruben Bartelink, don't have a citation, just general CLR knowledge, read CLR via C# by Jeffrey Richter, he explains all that I said.
Pop Catalin
you can simply create a test application with a structure and and instance method, and you will see that the instance method is called with a managed pointer to the structure not by passing a copy, or better yet use the dissasembly window in VS to inspect and instance method of a primitive/struct
Pop Catalin
Obv too long ago since I read it (and Applied .NET and Box and Skeet, me brags...). Upvote atcha!
Ruben Bartelink
It's one good reason i think, even if it could have easily be done in an instance method (nothing keep an instance method from working on a local copy).And it also comfort me in my choice of IsNaN properties instead of a static method as i'm dealing with Immutable data structures anyway.
VirtualBlackFox
@VirtualBlackFox If the instance method works on a local copy then it doesn't have instance semantics ;), instance methods are supposed to have side effects on the object they operate on, that's why a pointer to the structure/primitive is passed and not a copy.
Pop Catalin
@Pop Catalin: Yes and no, property getters shouldn't have side effects. I agree that making a copy of yourself maybe counter-intuitive but it is a way as an other to ensure thread safety.
VirtualBlackFox
What i mean is that if a `IsNaN` property is implemented the caller doesn't care if it is thread safe because there is a lock, a local copy or anything else, he only care to know if it is (or not) thread-safe.
VirtualBlackFox
You are right for the non-thread safety of immutable struct, sorry i never reflected on that.
VirtualBlackFox
Hmm... I don't think this shows that immutable structs aren't threadsafe. I think it shows that a new value can be copied over a whole mutable struct, even though its individual fields cannot be modified, and that this can happen while a method is running. In order to do that, the struct has to...
Daniel Earwicker
... be a member of a class. It's not obvious that 'bar' is a member of a class, but in fact it is. The compiler silently generates a hidden class because of the lambda.
Daniel Earwicker
@Earwicker it shows that structs always reside in volatile memory, and therefore instance methods are not thread safe, because instance methods access the struct through a pointer (a pointer to volatile memory).You can modify the app as you like (remove the lambda) and the result will be the same
Pop Catalin
Could you modify the code to show that? As far as I can make out, the problem is due to sharing the variable containing the value, which makes it possible to assign to that variable, changing the whole thing. So the variable has to be a member of a class, and then you are sharing one instance of ...
Daniel Earwicker
... that class between two threads. With the class written explicitly you may find it easier to see that locking is obviously required to protect access to that storage location. Without that, no method of reading/writing the struct is threadsafe (static or instance).
Daniel Earwicker
I talked over this with some C# friends. A value type instance method operates on the object in-place - it doesn't copy it. While the method is running, it's possible for another thread to replace the struct with another object. I was already anti-struct; now even more. ..
Jay Bazuzi
... but I will miss the free equality/hashcode behavior that you get with struct. I wish .Net equality wasn't so convoluted, and that C# made it easier to navigate.
Jay Bazuzi
A: 

I remember the words of a mentor, praying that any method, that does not use any other variables than the parameters are static methods.

I really do not know why, and havent thought on the behind, but logically, it seems good. Interested in the answer anyhow ;-)

BeowulfOF
I remember Scott Meyers saying that (altough about C++). Whether this was related to some performance or technical thing or just "taste" - I can't recall ;-)
Christian.K
Calling a static method with an boject parameter or an instance parameterless method should be exactly the same.The only thing that shouldn't be done is an instance method that isn't using the instance at all (And even this could be needed in some cases).
VirtualBlackFox
+2  A: 

@Pop Catalin: I'm not ok with what you said in :

If the structure is intended to be thread safe, then the methods should be made instance methods only if they do atomic operations, else static methods should be chosen.

Here is a small program that demonstrate that static methods don't solve this problem for structs :

using System;
using System.Threading;
using System.Diagnostics;

namespace ThreadTest
{
    class Program
    {
        struct SmallMatrix
        {
            double m_a, m_b, m_c, m_d;

            public SmallMatrix(double x)
            {
                m_a = x;
                m_b = x;
                m_c = x;
                m_d = x;
            }

            public static bool SameValueEverywhere(SmallMatrix m)
            {
                return (m.m_a == m.m_b)
                    && (m.m_a == m.m_c)
                    && (m.m_a == m.m_d);
            }
        }

        static SmallMatrix s_smallMatrix;

        static void Watcher()
        {
            while (true)
                Debug.Assert(SmallMatrix.SameValueEverywhere(s_smallMatrix));
        }

        static void Main(string[] args)
        {
            (new Thread(Watcher)).Start();
            while (true)
            {
                s_smallMatrix = new SmallMatrix(0);
                s_smallMatrix = new SmallMatrix(1);
            }
        }
    }
}

Note that this behavior can't be observed with double values on common processor as most x86 instructions have a version working with 64bits chunks such as movl.

So thread safety doesn't seem a good reason for IsNaN to be static :

  1. The framework should be platform agnostic and so it shouldn't presuppose things like the processor architecture. IsNaN thread-safety is dependent on the fact that 64bits values are always accessed and modified atomicaly on the target architecture (And Compact framework targets aren't x86...).
  2. IsNaN is useless by itself and in a context where multiple thread could access someVar this code is anyway unsafe (regardless of the thread safety of IsNaN) :
print("code sample");
if (!double.IsNaN(someVar))
    Console.WriteLine(someVar);

What i mean is that even if IsNaN is implemented by doing == comparisons with all possible NaN values... (not really possible) ...who care that the value evolve during the execution of the method if anyway it could have changed once the method terminate... or it could even be an intermediate value that should never have been here if the target architecture isn't x86...

Accessing intristic values in two different threads is NOT safe in general so i see no interest in providing some illusion of safety by putting any method static when dealing with structs or any other type,

VirtualBlackFox
Hmmm...guess I've might said it wrong, not thread safe, race condition free, once the struct is copied into the method stack, it can't be further modified, meaning if a static method does multiple operations on a struct, no race conditions will affect the value it recieved.
Pop Catalin
And besides there are many more issues with tread safety than even you said, things to consider are CPU caches, multi processors, etc. That doesn't mean static methods that operate on structs aren't thread safe. They are thread safe meaning they won't create race conditions.
Pop Catalin
Thread safety is not always about atomic operations is about 1) Not creating race conditions (Not IE modifying shared state) 2) not being affected by them (IE not working with shared state). Static methods do both 1) and 2). The static methods that accept values are thread safe ...
Pop Catalin
reading values and writing them is not, that's where you introduced a race in your application not in the static method.
Pop Catalin
My sample was writing values as yours was, if no one change the value where is the potential for race conditions ?What i meant is that static methods guard you against change while the method execute, but the change could also have happened while the copy to the stack was in progress.
VirtualBlackFox
The static method guarantee the caller that the method won't modify the struct behind his back, but i don't see any implementation of IsNaN modifying state. => I agree with your *1*, i just don't see why it could apply here.
VirtualBlackFox
As said previously my problem is with your *2* : Who care that IsNaN be guarded against race conditions inside itself?
VirtualBlackFox
I mean two choice here : You guarded the value with a lock or any other mechanism and so this guarantee is useless *OR* you haven't guarded it and the race condition may have happened while copying the value to the stack of the static IsNaN so this guarantee is useless.
VirtualBlackFox
Granted that it can't happen to double values on x86 systems as they are copied to the stack in one atomic operation. But it is dependent on architecture and doesn't apply to stucts.
VirtualBlackFox
"Who care that IsNaN be guarded against race conditions inside itself?" Because not doing so, creates security holes in a application. What happens if parameters passed to a method are modified after the method has determined they are safe? A method that writes to the file system for example.
Pop Catalin
Also passing a struct by value to a static method guarantees that the value the method received won't change, from method entry to method exit, this is where thread safety come from, not from reading the value and passing it to the method, which still need to be done atomically.
Pop Catalin
A: 

I think Marc was onto the answer.

The problem is when you need to call instance methods on valuetypes, the value is boxed. This would cause a severe performance penalty.

leppie
False, read chapter 13.3 of ECMA-335 (CIL) : """s thethis pointer. By contrast, instance and virtual methods of value types shall be coded to expect a managedpointer (see Partition I) to an unboxed instance of the value type. """
VirtualBlackFox