Search Unity

Reference vs integer as key

Discussion in 'Scripting' started by smittywerbenjagermanjesnen, Oct 27, 2020.

  1. smittywerbenjagermanjesnen

    smittywerbenjagermanjesnen

    Joined:
    Aug 30, 2020
    Posts:
    20
    Code (CSharp):
    1. List<int> one;
    2. List<MyClass> one;
    3.  
    4. Dictionary<int, SecondClass> two;
    5. Dictionary<MyClass, SecondClass> two;
    6.  
    7. //
    8.  
    9. if (one.Contains(x)) then...
    10. if (two.TryGetValue(x, out var y)) then...
    I assume int would perform better but MyClass is just a reference. int is unique identification of the MyClass. I could pass either int or MyClass as a key. The reason why I would like to use MyClass is for syntax, int requires additional attention of what that int is for, but MyClass literally tells programmer what its for.

    Is there any drawback of using references as keys in your experience?
     
  2. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    I don't really get your example. It should not even compile. List.Contains iterates over (in worst case) all elements. Dictionary.TryGetValue gets the right position straight by calculating the position. So it does not depend which type you look for but which collection you use. Using a reference type (class) as a dictionary index is done by hashing the values inside the class (which generates an int too) so it's computationally a bit more expensive than a straight int index. But if you need random search inside the collection the dictionary is O(1) whereas the List should be O(n) IIRC. So it highly depends on what you need to do in order to be able to tell which one is better. In case of doubt profile it. If you have no performance issues (yet) work on other stuff. Optimizations should ONLY be done WHEN there is a real bottleneck.

    Edit: typo
     
  3. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    542
    It's not directly a "drawback" but there are a few important things you should know. The dictionary uses the Equals and GetHashCode Methods to check the key.
    For an int it's simple, the hash code is the value it self and Equals for an int is also easy, it just compares the value.

    (The list Contains method only uses the Equals method(s) to find the entry)

    The default behavior of these methods for a class is Equals compares the runtime reference and GetHashCode returns the runtime "instance id", you can change this behavior by overriding these methods, you just have to make sure which logic should be used to compare the keys.

    So if you just want to check if the list/dictionary contains a specific instance, then the default methods should be fine, but if you need a more specific check then you have to override both method or you use the Dictionary constructor to pass a custom comparer which handles the logic instead of calling the GetHashCode and Equals methods on the objects directly).

    For example string is also a class but they override these methods so that it acts more like a value type, if you create multiple string instances which contain the same characters, they will return the same hash code and Equals will return true even when they are not the same reference. So in this case the List and Dictionary will find the "same" strings as keys even if you pass in a difference string instance, as long as both instances contain the same characters.
     
    Last edited: Oct 27, 2020
  4. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,116
    Probably stated above numerous times, but check out the key differences (no pun intended) between lists and dictionaries, otherwise you're in a world of pain.

    Whether or not your keys are references is irrelevant, if you're not using the proper collection for your data.

    btw, there is no difference whatsoever, GetHashCode is used for primitive values types as well.
     
  5. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    Using classes as your key is fine.

    The usual performance considerations apply when using references -- each requires space on the heap and should eventually become a garbage collection.

    If you use a class and want to override the Equals method, make sure you also override the GetHashCode method and follow the rules.