8 Replies - 7777 Views - Last Post: 01 June 2012 - 11:40 AM

#1 Momerath  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1010
  • View blog
  • Posts: 2,444
  • Joined: 04-October 09

C# quirks

Posted 15 May 2012 - 07:41 AM

Below you'll find a small block of code. Before running this code, make a prediction on what the output will be. After running the code, explain why it gave the output it did. Just FYI, this is not a bug, it's working as intended :)

using System;
using System.Collections.Generic;

namespace Sample {
    class Program {
        static void Main(string[] args) {
            MyStruct a;

            a.a = 1;
            a.b = 2;

            Dictionary<MyStruct, int> dic = new Dictionary<MyStruct, int>();
            dic.Add(a, 1);

            Console.WriteLine("{0}", dic[a]);

            a.a = 3;

            Console.WriteLine("{0}", dic[a]);

            Console.ReadLine();

        }
    }

    struct MyStruct {
        public int a;
        public int b;
    }
}



Is This A Good Question/Topic? 0
  • +

Replies To: C# quirks

#2 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3574
  • View blog
  • Posts: 11,114
  • Joined: 05-May 12

Re: C# quirks

Posted 31 May 2012 - 03:48 PM

Why do you call this a quirk? It failed as I expected.
Spoiler

Was This Post Helpful? 2
  • +
  • -

#3 Momerath  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1010
  • View blog
  • Posts: 2,444
  • Joined: 04-October 09

Re: C# quirks

Posted 31 May 2012 - 08:46 PM

View PostSkydiver, on 31 May 2012 - 03:48 PM, said:

Why do you call this a quirk? It failed as I expected.

It's something you need to be aware of when you create your own value types and override GetHashCode(). It also shows that the default System.ValueType.GetHashCode() isn't very useful.
Was This Post Helpful? 0
  • +
  • -

#4 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2113
  • View blog
  • Posts: 3,235
  • Joined: 21-June 11

Re: C# quirks

Posted 01 June 2012 - 02:34 AM

View PostMomerath, on 01 June 2012 - 05:46 AM, said:

View PostSkydiver, on 31 May 2012 - 03:48 PM, said:

Why do you call this a quirk? It failed as I expected.

It's something you need to be aware of when you create your own value types and override GetHashCode(). It also shows that the default System.ValueType.GetHashCode() isn't very useful.


Why is it not useful? Doesn't it match exactly what you'd define your own GetHashCode to do anyway in most of the cases?

Basically when you don't override GetHashCode two objects of the same value type will be seen as the same key if they contain the same content. While two reference types with the same contents will not seen as the same key (unless you override GetHashCode and Equals). To me (and I expect most people) the latter is the less useful behavior.

Just imagine what would happen (ignoring string interning for the moment) if String didn't override GetHashCode: mydict["foo"] = 42; mydict["foo"] would tell you that the key "foo" was not found in the dictionary. In my mind that wouldn't be desirable behavior. Value types simply get the GetHashCode method for free, that reference types like String have to define for themselves.

Also note that using a mutable reference type (which overrides GetHashCode and equals in a meaningful way) as a dictionary key and then mutating it often makes the key unaccessible (because it's stored at a location determined by its contents at insertion time, but it no longer compares equal to anything that would be stored at that location). This kind of thing also doesn't happen with value types.
Was This Post Helpful? 0
  • +
  • -

#5 Momerath  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1010
  • View blog
  • Posts: 2,444
  • Joined: 04-October 09

Re: C# quirks

Posted 01 June 2012 - 07:10 AM

View Postsepp2k, on 01 June 2012 - 02:34 AM, said:

Why is it not useful? Doesn't it match exactly what you'd define your own GetHashCode to do anyway in most of the cases?

It's not useful because there is no requirement that value types be unmutable (just a suggestion that they be). Collections that use the hash code then become less functional unless you implement a hash code that doesn't depend on the content of the value type (sort of like what they did with System.Object.GetHashCode()). Even Microsoft doesn't follow the unmutable value type 'rule' (see System.Drawing.Point as an example).
Was This Post Helpful? 0
  • +
  • -

#6 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2113
  • View blog
  • Posts: 3,235
  • Joined: 21-June 11

Re: C# quirks

Posted 01 June 2012 - 08:25 AM

View PostMomerath, on 01 June 2012 - 04:10 PM, said:

View Postsepp2k, on 01 June 2012 - 02:34 AM, said:

Why is it not useful? Doesn't it match exactly what you'd define your own GetHashCode to do anyway in most of the cases?

It's not useful because there is no requirement that value types be unmutable (just a suggestion that they be).


There's no requirement or suggestion that reference types be immutable. You'd still define a reference type's GetHashCode method to depend on its contents if you intend to use it as a hash key.

Quote

Collections that use the hash code then become less functional unless you implement a hash code that doesn't depend on the content of the value type (sort of like what they did with System.Object.GetHashCode()).


I don't understand that reasoning. The only way for a value type's GetHashCode to not depend on its contents, would be to always return the same hash code (since obviously it couldn't depend on its "object identity" since that concept does not apply to value types). How would that make them more functional?

For that matter how does the fact that a reference type's default GetHashCode method depends on its object identity enhance its functionality? Can you tell me a scenario in which you'd ever use a reference type as a hash key without overriding its GetHashCode method to not depend on its object identity first (preferably one that would also be useful to value types)?
Was This Post Helpful? 0
  • +
  • -

#7 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon


Reputation: 2262
  • View blog
  • Posts: 9,466
  • Joined: 29-May 08

Re: C# quirks

Posted 01 June 2012 - 08:25 AM

Do you mean immutable? Momerath
Was This Post Helpful? 0
  • +
  • -

#8 Momerath  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1010
  • View blog
  • Posts: 2,444
  • Joined: 04-October 09

Re: C# quirks

Posted 01 June 2012 - 11:18 AM

View PostAdamSpeight2008, on 01 June 2012 - 08:25 AM, said:

Do you mean immutable? Momerath

Yes I do :) I was trying to edit it when D.I.C. crashed on me (database errors).

View Postsepp2k, on 01 June 2012 - 08:25 AM, said:

There's no requirement or suggestion that reference types be immutable. You'd still define a reference type's GetHashCode method to depend on its contents if you intend to use it as a hash key.

Not talking about reference types at all, and I wouldn't override GetHashCode at all, unless I was trying to improve performance. Not sure why you think you would override it for a reference type.

Quote

I don't understand that reasoning. The only way for a value type's GetHashCode to not depend on its contents, would be to always return the same hash code (since obviously it couldn't depend on its "object identity" since that concept does not apply to value types). How would that make them more functional?

That isn't the only way to implement GetHashCode for a value type so your argument is moot.

Quote

For that matter how does the fact that a reference type's default GetHashCode method depends on its object identity enhance its functionality? Can you tell me a scenario in which you'd ever use a reference type as a hash key without overriding its GetHashCode method to not depend on its object identity first (preferably one that would also be useful to value types)?

Really? You derive your own class for every object and override GetHashCode before you use it in a Dictionary or a HashTable? I really don't understand what point you are trying to make here.
Was This Post Helpful? 0
  • +
  • -

#9 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2113
  • View blog
  • Posts: 3,235
  • Joined: 21-June 11

Re: C# quirks

Posted 01 June 2012 - 11:40 AM

View PostMomerath, on 01 June 2012 - 08:18 PM, said:

Not talking about reference types at all, and I wouldn't override GetHashCode at all, unless I was trying to improve performance. Not sure why you think you would override it for a reference type.


Most reference types in the standard library (at least those that would be reasonably used as keys in dictionaries) override GetHashCode. That includes the string class (which is probably the most common type for keys in dictionaries). They do so for the reason that I already mentioned: if you did something like myDict["foo"] = bar; myDict["foo"];, you'd want to get back bar and not an error. The same reasoning applies when defining your own class.


Quote

Quote

I don't understand that reasoning. The only way for a value type's GetHashCode to not depend on its contents, would be to always return the same hash code (since obviously it couldn't depend on its "object identity" since that concept does not apply to value types). How would that make them more functional?

That isn't the only way to implement GetHashCode for a value type so your argument is moot.


That's the only way to implement GetHashCode that doesn't depend on the object's contents.

Quote

Quote

For that matter how does the fact that a reference type's default GetHashCode method depends on its object identity enhance its functionality? Can you tell me a scenario in which you'd ever use a reference type as a hash key without overriding its GetHashCode method to not depend on its object identity first (preferably one that would also be useful to value types)?

Really? You derive your own class for every object and override GetHashCode before you use it in a Dictionary or a HashTable? I really don't understand what point you are trying to make here.


I was talking about a scenario where you were defining your own class anyway, you wanted it to be usable as a key in dictionaries and you did not override GetHashCode.

The existing classes that I would use as dictionary keys already override GetHashCode, so there'd be no need for me to do so myself.

This post has been edited by sepp2k: 01 June 2012 - 11:40 AM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1