Search Unity

Hit A Wall of Incomprehension - classes, instances, pass by reference

Discussion in 'Scripting' started by Swankington, Jun 6, 2018.

  1. Swankington

    Swankington

    Joined:
    Jul 27, 2013
    Posts:
    6
    Hello. I have again run into one of these times where I waste half an afternoon trying to fix a problem when I don't know what is causing it to begin with. Either I don't understand Unity, or it doesn't understand me.

    I have taught myself C# and Unity with a fairly rudimentary background in C++. I thought I understood how classes and instances work. I have a game that I have been working on for years and have never run into this problem before despite making copious use of classes and never one having this pass by reference issue because all the classes, in every case, and in this case where it is not working as well, are instanced.

    These are the classes I am attempting to use. They are nested, gearProperty goes inside battleGear which goes inside gearProfile. Perhaps this nested character is causing issues? Ignore the SameGear function in battleGear it was when I was attempting to make battleGear a struct rather than a class, which apparently made no difference to the passing by reference, again baffling.

    Code (csharp):
    1.  
    2.  
    3. public class gearProperty
    4. {
    5.     public string propertyName;
    6.     public int propertyLevel;
    7.  
    8.     public gearProperty(string pName, int pLevel)
    9.     {
    10.         propertyName = pName;
    11.         propertyLevel = pLevel;
    12.     }
    13.  
    14.     public gearProperty()
    15.     {
    16.  
    17.     }
    18.  
    19. }
    20.  
    21. public class battleGear
    22. {
    23.     public string gearName;
    24.     public string gearType;
    25.     public string gearSubType;
    26.     public List<gearProperty> gearProperties;
    27.     public string gearDescription;
    28.  
    29.     public battleGear(string gName, string gType, string gSType, List<gearProperty> gProperties, string gDescript)
    30.     {
    31.         gearName = gName;
    32.         gearType = gType;
    33.         gearSubType = gSType;
    34.         gearProperties = gProperties;
    35.         gearDescription = gDescript;
    36.     }
    37.  
    38.     public battleGear()
    39.     {
    40.  
    41.     }
    42.  
    43.  
    44.     public int ReturnPropertyLevel(string input)
    45.     {
    46.         foreach (gearProperty prop in gearProperties)
    47.         {
    48.             if (prop.propertyName == input) return prop.propertyLevel;
    49.         }
    50.         return 0;
    51.     }
    52.  
    53.     public bool SameGear(battleGear otherGear)
    54.     {
    55.         bool isSame = true;
    56.  
    57.         if (otherGear.gearName != gearName) isSame = false;
    58.         if (otherGear.gearType != gearType) isSame = false;
    59.         if (otherGear.gearSubType != gearSubType) isSame = false;
    60.         if (otherGear.gearSubType != gearSubType) isSame = false;
    61.         if (otherGear.gearProperties != gearProperties) isSame = false;
    62.         if (otherGear.gearDescription != gearDescription) isSame = false;
    63.  
    64.         return isSame;
    65.  
    66.     }
    67. }
    68.  
    69.  
    70. public class gearProfile
    71. {
    72.     public string profileName;
    73.     public battleGear mainWeapon;
    74.     public battleGear offWeapon;
    75.     public battleGear altWeapon;
    76.     public battleGear throwing;
    77.     public battleGear armor;
    78.     public battleGear cloak;
    79.     public battleGear accessory;
    80.     public battleGear useItem;
    81.  
    82.     public bool ExistsInArmory(battleGear pickedGear, List<battleGear> armory)
    83.     {
    84.         foreach (battleGear gear in armory)
    85.         {
    86.             if (gear.SameGear(pickedGear)) return true;
    87.         }
    88.  
    89.         return false;
    90.     }
    91.  
    92.     public int ScanAllGearForHighestProperty(string propName)
    93.     {
    94.         int propLevel = 0;
    95.  
    96.         if (mainWeapon.ReturnPropertyLevel(propName) > propLevel) propLevel = mainWeapon.ReturnPropertyLevel(propName);
    97.         if (offWeapon.ReturnPropertyLevel(propName) > propLevel) propLevel = offWeapon.ReturnPropertyLevel(propName);
    98.         if (altWeapon.ReturnPropertyLevel(propName) > propLevel) propLevel = altWeapon.ReturnPropertyLevel(propName);
    99.         if (throwing.ReturnPropertyLevel(propName) > propLevel) propLevel = throwing.ReturnPropertyLevel(propName);
    100.         if (cloak.ReturnPropertyLevel(propName) > propLevel) propLevel = cloak.ReturnPropertyLevel(propName);
    101.         if (armor.ReturnPropertyLevel(propName) > propLevel) propLevel = armor.ReturnPropertyLevel(propName);
    102.         if (accessory.ReturnPropertyLevel(propName) > propLevel) propLevel = accessory.ReturnPropertyLevel(propName);
    103.         if (useItem.ReturnPropertyLevel(propName) > propLevel) propLevel = useItem.ReturnPropertyLevel(propName);
    104.  
    105.         return propLevel;
    106.     }
    107.  
    108.     public int ScanAllGearForCumulativeProperty(string propName)
    109.     {
    110.         int propLevel = 0;
    111.  
    112.         if (mainWeapon.ReturnPropertyLevel(propName) > propLevel) propLevel += mainWeapon.ReturnPropertyLevel(propName);
    113.         if (offWeapon.ReturnPropertyLevel(propName) > propLevel) propLevel += offWeapon.ReturnPropertyLevel(propName);
    114.         if (altWeapon.ReturnPropertyLevel(propName) > propLevel) propLevel += altWeapon.ReturnPropertyLevel(propName);
    115.         if (throwing.ReturnPropertyLevel(propName) > propLevel) propLevel += throwing.ReturnPropertyLevel(propName);
    116.         if (cloak.ReturnPropertyLevel(propName) > propLevel) propLevel += cloak.ReturnPropertyLevel(propName);
    117.         if (armor.ReturnPropertyLevel(propName) > propLevel) propLevel += armor.ReturnPropertyLevel(propName);
    118.         if (accessory.ReturnPropertyLevel(propName) > propLevel) propLevel += accessory.ReturnPropertyLevel(propName);
    119.         if (useItem.ReturnPropertyLevel(propName) > propLevel) propLevel += useItem.ReturnPropertyLevel(propName);
    120.  
    121.         return propLevel;
    122.     }
    123.  
    124.     public gearProfile(string pName, battleGear mW, battleGear oW, battleGear aW, battleGear tW, battleGear c, battleGear ar, battleGear ac, battleGear uI)
    125.     {
    126.         profileName = pName;
    127.         mainWeapon = mW;
    128.         offWeapon = oW;
    129.         altWeapon = aW;
    130.         throwing = tW;
    131.         armor = ar;
    132.         cloak = c;
    133.         accessory = ac;
    134.         useItem = uI;
    135.     }
    136.  
    137.     public gearProfile(battleGear mW, battleGear oW, battleGear aW, battleGear tW, battleGear c, battleGear ar, battleGear ac, battleGear uI)
    138.     {
    139.         profileName = "Default";
    140.         mainWeapon = mW;
    141.         offWeapon = oW;
    142.         altWeapon = aW;
    143.         throwing = tW;
    144.         armor = ar;
    145.         cloak = c;
    146.         accessory = ac;
    147.         useItem = uI;
    148.     }
    149.  
    150.     public gearProfile()
    151.     {
    152.  
    153.     }
    154.  
    155. }
    156.  
    So to a Unity object I add this BattleGearLibrary script which includes these class declarations, and I declare an instance of a List of battleGear, just like I always do, a la "List<battleGear> battleGearCodex = new List<battleGear>();". However, no matter what I do, any changes to any battleGear, even from an apparently separate instance, in a separate script, where I have declared "battleGear temp = new battleGear();", changes the originals in battle gear codex list. I have not run into this problem before. Somehow it is not instancing off the class properly. Either I am misunderstanding something completely rudimentary, which is certainly possible and even likely, or there is some genuine glitch occurring here.Thank you for any insight y'all have into this. I got deadlines and I am losing a bit of sleep.

    Let me know if you need more info.
     
    Last edited: Jun 6, 2018
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    Lets start with using code tags:
    https://forum.unity.com/threads/using-code-tags-properly.143875/

    Code (csharp):
    1. public class gearProperty
    2. {
    3.     public string propertyName;
    4.     public int propertyLevel;
    5.  
    6.     public gearProperty(string pName, int pLevel)
    7.     {
    8.         propertyName = pName;
    9.         propertyLevel = pLevel;
    10.     }
    11.  
    12.     public gearProperty()
    13.     {
    14.  
    15.     }
    16.  
    17. }
    18.  
    19. public class battleGear
    20. {
    21.     public string gearName;
    22.     public string gearType;
    23.     public string gearSubType;
    24.     public List<gearProperty> gearProperties;
    25.     public string gearDescription;
    26.  
    27.     public battleGear(string gName, string gType, string gSType, List<gearProperty> gProperties, string gDescript)
    28.     {
    29.         gearName = gName;
    30.         gearType = gType;
    31.         gearSubType = gSType;
    32.         gearProperties = gProperties;
    33.         gearDescription = gDescript;
    34.     }
    35.  
    36.     public battleGear()
    37.     {
    38.  
    39.     }
    40.  
    41.  
    42.     public int ReturnPropertyLevel(string input)
    43.     {
    44.         foreach (gearProperty prop in gearProperties)
    45.         {
    46.             if (prop.propertyName == input) return prop.propertyLevel;
    47.         }
    48.         return 0;
    49.     }
    50.  
    51.     public bool SameGear(battleGear otherGear)
    52.     {
    53.         bool isSame = true;
    54.  
    55.         if (otherGear.gearName != gearName) isSame = false;
    56.         if (otherGear.gearType != gearType) isSame = false;
    57.         if (otherGear.gearSubType != gearSubType) isSame = false;
    58.         if (otherGear.gearSubType != gearSubType) isSame = false;
    59.         if (otherGear.gearProperties != gearProperties) isSame = false;
    60.         if (otherGear.gearDescription != gearDescription) isSame = false;
    61.  
    62.         return isSame;
    63.  
    64.     }
    65. }
    66.  
    67.  
    68. public class gearProfile
    69. {
    70.     public string profileName;
    71.     public battleGear mainWeapon;
    72.     public battleGear offWeapon;
    73.     public battleGear altWeapon;
    74.     public battleGear throwing;
    75.     public battleGear armor;
    76.     public battleGear cloak;
    77.     public battleGear accessory;
    78.     public battleGear useItem;
    79.  
    80.     public bool ExistsInArmory(battleGear pickedGear, List<battleGear> armory)
    81.     {
    82.         foreach (battleGear gear in armory)
    83.         {
    84.             if (gear.SameGear(pickedGear)) return true;
    85.         }
    86.  
    87.         return false;
    88.     }
    89.  
    90.     public int ScanAllGearForHighestProperty(string propName)
    91.     {
    92.         int propLevel = 0;
    93.  
    94.         if (mainWeapon.ReturnPropertyLevel(propName) > propLevel) propLevel = mainWeapon.ReturnPropertyLevel(propName);
    95.         if (offWeapon.ReturnPropertyLevel(propName) > propLevel) propLevel = offWeapon.ReturnPropertyLevel(propName);
    96.         if (altWeapon.ReturnPropertyLevel(propName) > propLevel) propLevel = altWeapon.ReturnPropertyLevel(propName);
    97.         if (throwing.ReturnPropertyLevel(propName) > propLevel) propLevel = throwing.ReturnPropertyLevel(propName);
    98.         if (cloak.ReturnPropertyLevel(propName) > propLevel) propLevel = cloak.ReturnPropertyLevel(propName);
    99.         if (armor.ReturnPropertyLevel(propName) > propLevel) propLevel = armor.ReturnPropertyLevel(propName);
    100.         if (accessory.ReturnPropertyLevel(propName) > propLevel) propLevel = accessory.ReturnPropertyLevel(propName);
    101.         if (useItem.ReturnPropertyLevel(propName) > propLevel) propLevel = useItem.ReturnPropertyLevel(propName);
    102.  
    103.         return propLevel;
    104.     }
    105.  
    106.     public int ScanAllGearForCumulativeProperty(string propName)
    107.     {
    108.         int propLevel = 0;
    109.  
    110.         if (mainWeapon.ReturnPropertyLevel(propName) > propLevel) propLevel += mainWeapon.ReturnPropertyLevel(propName);
    111.         if (offWeapon.ReturnPropertyLevel(propName) > propLevel) propLevel += offWeapon.ReturnPropertyLevel(propName);
    112.         if (altWeapon.ReturnPropertyLevel(propName) > propLevel) propLevel += altWeapon.ReturnPropertyLevel(propName);
    113.         if (throwing.ReturnPropertyLevel(propName) > propLevel) propLevel += throwing.ReturnPropertyLevel(propName);
    114.         if (cloak.ReturnPropertyLevel(propName) > propLevel) propLevel += cloak.ReturnPropertyLevel(propName);
    115.         if (armor.ReturnPropertyLevel(propName) > propLevel) propLevel += armor.ReturnPropertyLevel(propName);
    116.         if (accessory.ReturnPropertyLevel(propName) > propLevel) propLevel += accessory.ReturnPropertyLevel(propName);
    117.         if (useItem.ReturnPropertyLevel(propName) > propLevel) propLevel += useItem.ReturnPropertyLevel(propName);
    118.  
    119.         return propLevel;
    120.     }
    121.  
    122.     public gearProfile(string pName, battleGear mW, battleGear oW, battleGear aW, battleGear tW, battleGear c, battleGear ar, battleGear ac, battleGear uI)
    123.     {
    124.         profileName = pName;
    125.         mainWeapon = mW;
    126.         offWeapon = oW;
    127.         altWeapon = aW;
    128.         throwing = tW;
    129.         armor = ar;
    130.         cloak = c;
    131.         accessory = ac;
    132.         useItem = uI;
    133.     }
    134.  
    135.     public gearProfile(battleGear mW, battleGear oW, battleGear aW, battleGear tW, battleGear c, battleGear ar, battleGear ac, battleGear uI)
    136.     {
    137.         profileName = "Default";
    138.         mainWeapon = mW;
    139.         offWeapon = oW;
    140.         altWeapon = aW;
    141.         throwing = tW;
    142.         armor = ar;
    143.         cloak = c;
    144.         accessory = ac;
    145.         useItem = uI;
    146.     }
    147.  
    148.     public gearProfile()
    149.     {
    150.  
    151.     }
    152.  
    153. }
     
    hippocoder likes this.
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    As for your problem:

    So you show us these class declarations.

    But what of the code where you create and use these classes?

    I see potential issues arrising depending how you use these classes. For example 'battleGear' takes in a 'List<gearProperty>'. Thing is you just store that reference. List<T> is a ref type so that means if you go and continue using that list for more instance's of 'battleGear', you're going to be effecting the list's of previously created battleGears.
     
    Owen-Reynolds likes this.
  4. Swankington

    Swankington

    Joined:
    Jul 27, 2013
    Posts:
    6
    Thanks for telling me about code tags! The code is really simple here's the snippets that are essentially not working how I expected.

    Code (csharp):
    1.  
    2. void Awake()
    3.     {
    4.         battleGearCodex = new List<battleGear>();
    5.         npcGearProfiles = new List<gearProfile>();
    6.         InitGearInfo(); //This loads a bunch of preset battleGear into the list,
    7.         InitNPCProfileInfo(); //This uses the presets from the just created list to create gearProfiles
    8.     }
    9.  
    10.  public battleGear LookupBattleGearInfo(string query)
    11.     {
    12.         battleGear returnGear = new battleGear();
    13.  
    14.         foreach (battleGear gear in battleGearCodex)
    15.         {
    16.            
    17.             if (gear.gearName == query)
    18.             {
    19.                 returnGear = gear;
    20.             }
    21.         }
    22.  
    23.         return returnGear;
    24.     }
    25.  
    26.  void InitNPCProfileInfo()
    27.     {
    28.        //This is just one profile, there are about twenty total right now
    29.         tempProfile = new gearProfile();
    30.         tempProfile.profileName = "Bow Militia";
    31.         tempProfile.mainWeapon = LookupBattleGearInfo("Short Bow");
    32.         tempProfile.offWeapon = LookupBattleGearInfo("Empty");
    33.         tempProfile.altWeapon = LookupBattleGearInfo("Dagger");
    34.         tempProfile.throwing = LookupBattleGearInfo("Hide Quiver");
    35.         //!This is the issue, when I add a new property to the new gear in the gear profile, it edits the original in the list!
    36.         tempProfile.throwing.gearProperties.Add(new gearProperty("Broadhead", 12));
    37.      
    38.         tempProfile.cloak = LookupBattleGearInfo("Greatcloak");
    39.         tempProfile.armor = LookupBattleGearInfo("Empty");
    40.         tempProfile.accessory = LookupBattleGearInfo("Empty");
    41.         tempProfile.useItem = LookupBattleGearInfo("Empty");
    42.  
    43.         npcGearProfiles.Add(tempProfile);
    44.    }
    45.  
    So, the List<> is by reference? :D How is it possible that I have successfully made anything without understanding that? Oh well. Is there a different way to make a list of values that has escaped my notice for years? Thank you so much for your help.
     
  5. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    If you know C++, it's easiest to skip the C# nomenclature. All C# class variables are just implicitly dereferenced pointers. So List&lt;battleGear&gt; G; is a list of pointers. G.price is secretly running G-&gt;price.

    Classes aren't passed by reference. As normal, you're passing a pointer by value. I can't follow your code, but I think LoD is correct. In C# Lists and even arrays are simple non-const pointers. doStuffwith(GearList) passes a pointer to the original gearlist. C# will never automatically make a real copy of a class for you, unless you run L2=L1.clone() (I think). Which you almost never need.

    So, and again, just what LoD mentioned, when you have myGearProp=inputGearProp;, decide if you want a pointer to the same list (which that gives you,) or a new list which will start as a copy of the old one.
     
  6. kru

    kru

    Joined:
    Jan 19, 2013
    Posts:
    452
    Code (csharp):
    1. // If you want to conveniently perform a shallow copy of a list
    2. List<T> otherList = some list
    3. var myList = new List<T>(otherList);
    4. // Now mylist and otherlist are two separate lists, so adding and removing from one wont affect the other
    5. // But each element of the lists point to the same object
     
  7. Swankington

    Swankington

    Joined:
    Jul 27, 2013
    Posts:
    6
    So I've been treating C# as if it were C++, and the fact that custom classes and variables are actually dereferenced pointers as you say seems to not have come up until this very moment for some inexplicable reason. Perhaps a few other bugs might be explained by this.

    I understand that a list is just a collection of pointers TO data, and pointers to other pointers, so once you create a list with new List<string>(), all you're really doing is saying set aside memory for storing pointers back to the data, not the data itself. But where the hell was the first "instance" stored in the first place? The data exists somewhere, but not anywhere specific, and is only findable from the list pointer?

    I thought perhaps replacing all classes with structs in this case should fix it, but if you have a struct with a list in it, I assume you have the same damn set of problems. How the hell do I make an arbitrarily long list of genuine data that I can read from but will not automatically write back to? I've tried "cloning" and that seems to do nothing.

    I just revamped my battle system with some nice compact classes for "elegance" and it turns out the crummy way I was doing it before with the whole set of variables assigned to Script objects was actually what I wanted, values. So weird.
     
    Last edited: Jun 6, 2018
  8. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    My longer explanation is in the "C# for C++ programmers" at my taxesforcatses.com site.

    But briefly: C# uses "Reference Types" the same as Java. Basic types can't have pointers and are always copied. Reference Types can only be implicit pointers to heap objects, and can never be declared as simple storage. C# says structs are NON-reference types. So, unlike in C++, C# structs and classes are completely different beasts.

    List<string> L=new List<string>(); declares L as a pointer to a string-List on the heap. Most C# coders _think_ of that as a single object. But, for example, L2=L; L=null; will "transfer ownership" to L2, as per regular pointer use.

    String works like a basic type. List<int> or string stores them directly. But List<someClass> L is a pointer to a list storing pointers. To make it more confusing, basic types use a fake NEW. w=new string(); or myStruct=new myStruct(3,7); does NOT allocate heap storage. The NEW is for decorative purposes only.
     
  9. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Are you sure about strings? I'm fairly certain they are reference-counted types, just like any other class instances in C#. They merely act like values because they are immutable (from the outside, there is no way to tell an immutable reference type from a value type).

    (If you dig this sort of thing, you may enjoy this essay on why Python is pass-by-value, which I wrote years ago because the vast majority of Python users were entirely confused on this point and would argue nonsensical positions about it at great length.)

    Incidentally C#, just like Java, Python, REALbasic, etc., is pass-by-value, unless you explicitly add a "ref" or "out" modifier.
     
  10. TimmyTheTerrible

    TimmyTheTerrible

    Joined:
    Feb 18, 2017
    Posts:
    186
    You have to watch out with references, using reference1 = reference2 is going to make reference1 refer to the same copy of data as reference2.

    Even if you do reference1 = new Type (), and then say go reference1 = reference2, Well all you did was create a new instance of the class, and then discard it, because now reference1 isn't pointing at the new instance anymore. It's pointing at reference2's data now.

    So if your looking to copy gear into a list with it's own instances of the data to modify, you have to use the new keyword and pass in the new data types from the class manually, instead of class1 = class2 .

    Cloning a reference type doesn't really do anything either because your still pointing at the exact same data.

    If you want to copy data between classes, make a custom constructor that actually copies the data from one class instance to another:

    Code (CSharp):
    1. class Battlegear
    2. {
    3.    int value;
    4.  
    5.    Battlegear (Battlegear copy)
    6.    {
    7.       value = copy.value;
    8.    }
    9. }
    10.  
    11. // This will have both classes refer to the exact same data
    12. Battlegear gear2 = gear1;
    13.  
    14. // This will copy the data from gear1 to a new, separate instance.
    15. Battlegear gear2 = new Battlegear (gear1);
     
    JoeStrout likes this.
  11. Swankington

    Swankington

    Joined:
    Jul 27, 2013
    Posts:
    6
    Thanks so much everyone. I think I can make this work. You've been immeasurably helpful.
     
    eisenpony and JoeStrout like this.
  12. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    String is actually a really weird type inside.

    But yes, it's a reference type that 'may' end up on the heap depending.

    And what I mean by that is that strings may instead end up in a special pool of memory called the 'intern pool'. This block of memory is located on the LOH (large object heap), but is a special allocated spot of it (and is managed in a slightly different way as a result). You could argue it's therefore on the heap, but that's a semantics thing. All memory can be stored in the same places... it's how you 'treat' that memory that makes it what is in regards to .net/mono, and well, this block of memory is treated slightly different than other objects on the LOH.

    String literals in your code (strings just declared inline) are interned. This way duplicate string literals take up much less memory. Where as strings you create a runtime will usually end up on the normal heap (unless a string exists of it in the intern pool, and you generated it in a manner that checks the intern pool). You can also intern strings at runtime with the string.Intern method:
    https://msdn.microsoft.com/en-us/library/system.string.intern(v=vs.110).aspx

    A weird added benefit of interned strings is that they 'might' compare faster because comparison checks for strings actually test 'reference' first before comparing char by char. So if 2 strings reference the same interned string, they're the same ref, and will succeed immediately.

    Of course, Unity throws a wrench into this. I don't know how the older mono that Unity uses has its intern pool setup... I know it exists, just I don't know how robust it is. I also know that Unity doesn't use it at all when returning strings from the Unity api... this is obvious because you can call 'name' over and over with out changing it, and it'll repeatedly return 'new' strings.
     
    JoeStrout and eisenpony like this.
  13. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    I think its pretty baffling you have been able to code a game "for years" without understanding the basics of reference/value types in C# :D
     
  14. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    fun story:

    I once had a junior dev that though the equals operator of a object in javascript would return true if the objects logically were the same. So

    Code (CSharp):
    1. Assert.IsTrue(new MyType { Id = 5, Name = "foo" } ==  new MyType { Id = 5, Name = "foo" });
    Would be true :p
     
  15. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    That's why they're "juniors", they don't know these things yet.

    Without specific knowledge of the language in question, it is reasonable to guess they could be equal.

    Aw man, this 4 year old I know, he can't even spell his own name! :p
     
  16. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    In this case he was a Computer science master or bachelor though. If the 4 year old had a degree in English and couldn't spell his name it would have been a different story :p
     
  17. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    Computer science bachelor != javascript.

    Lets say it was C, and he created 2 structs with those values, they would be equal.

    Whatever though, if you want to make fun of some guy we don't know, have at it.
     
    eisenpony likes this.
  18. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    I hope they still learn students not to take behaviour for granted
     
  19. Swankington

    Swankington

    Joined:
    Jul 27, 2013
    Posts:
    6
    It is very strange. But because in literally every case before this I believe the instanced class was attached to a separate script object it automatically behaved as values. It seems preposterous in retrospect. But of course, the whole point of C# using the dereferenced pointers thing is that it is more efficient than continually storing more data unnecessarily, right? But C# was so cosmetically similar to C++ that I didn't notice, say, this key fundamental difference.

    And my game, that I've been working on by myself, yes, for years, has over 80% positive reviews on Steam, so I got chops enough for that.
     
  20. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    C# is like C++ in the sense it's C-like cosmetically. Just like Java is C-like. But it borrows way more for Java than it does from C++. Way way way more.

    C# is managed, and as a result the memory is handled for you. So everything is just approached in a very different manner. It has nothing to do with storing more data unnecessarily. And more to do with just how the concept of automatic memory management works fundamentally.

    Really, beyond cosmetic syntax, there's not a lot of parallels you can draw from C++ under the hood, especially in regards to memory.
     
  21. kru

    kru

    Joined:
    Jan 19, 2013
    Posts:
    452
    Depends on the definition of MyType, doesn't it?
    Code (csharp):
    1.  
    2. public class MyType
    3. {
    4.     public int Id;
    5.     public string Name;
    6.    
    7.     public static bool operator == (MyType a, MyType b)
    8.     {
    9.         return a.Id == b.Id && string.CompareOrdinal(a.Name, b.Name) == 0;
    10.     }
    11.  
    12.     public static bool operator !=(MyType a, MyType b)
    13.     {
    14.         return !(a == b);
    15.     }
    16. }
     
    lordofduct likes this.
  22. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    Or:

    Code (csharp):
    1.  
    2. public struct MyType
    3. {
    4.     public int Id;
    5.     public string Name;
    6. }
    7.  
    But yeah, he said it in the context of 'javascript'. Which is true, in javascript, there's no scenario that'd be equal since they're just a "plain old object".

    But that's the thing. It's a distinct piece of knowledge specific to javascript. And a computer science bachelors degree doesn't necessarily teach you 'javascript'. Hell, it might not even teach one line of javascript depending the curriculum (though that's a little odd). But there's nothing about "Computer Science Degree" that means "Javascript Programmer"... though, I will say after over a decade of working in various offices, and being on the hiring side of the table, I've worked with many managers who assume that's what "Computer Science Degree" means.

    I often found myself saying "I think you're looking for a tech school grad, someone who took a crashcourse in 'language X'..."

    "No, I want a college grad damn it! What are these schools even teaching them?"

    "Well... clearly not all of the languages under the sun."

    But of course, 9 times out of 10, in an office 'junior' isn't meant to mean "entry level" it's expected to mean "intermediate level at entry level pay grade".
     
  23. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    In javascript you cant overload operators. Anyway, if you didn't write the class yourself and are using it you dont do a equals operation before checking if it has a equals operator override, right?

    edit: What I mean is in C# you should expect it to be a reference comparison nothing else before checking the implementation.
     
  24. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    The fact a conversation of the nuances of language features can be had by a group of experienced professionals is the point we're trying to convey to you about your expectations of a 'junior' developer.
     
  25. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    The basics of class references work the same in any object oriented language though
     
  26. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    Not necessarily, as was pointed out already.

    Also, your original comments about this weren't about classes, but rather about plain old objects in javascript:
    Also I could get pedantic about what counts as a class and there are arguments made that technically speaking javascript doesn't really have classes in the classical sense. But rather has function prototyping which can be used to get class like functionality that only in recent years has been given a special keyword of 'class'.

    And anyways, 'Computer Science Degree' just like it isn't technically a degree in 'javascript', it's also not a degree in 'object oriented languages'. It is a degree in, as the name suggests, computer science. It's basically the systematic study of algorithms. You don't take CS to learn to program, programming is incidental to Computer Science. A CS degree is more about learning the fundamentals of how computer programming works and why we do it the way we do. And well since OOP is only a tiny part of programming in general, a bachelor in it may not have spent a whole lot of time in OOP. We're talking OOP is maybe a few chapters of a semester, or maybe at best an entire semester if you happen to take a semester covering a specific OOP language (like a Java course). But yeah, you usually spend your time learning about the multiple 'sorting' algorithms and how they were developed. Machine language. How compilers work and how to make one. That sort of stuff.

    It's like expecting the fresh out of school civil engineer who shows up on the job site, and one of the construction workers calls him a dolt because he doesn't know that a Craftsman hammer is S***e. Sure he should know how to swing a hammer, but he probably isn't aware of the nuances of swinging one on a daily basis because that's not what he spent 4 years in college doing.

    But eh, I might not know what I'm talking about. I'm just a lowly programmer, I don't have a CS degree. I dropped out of college, and I was only studying to be a math teacher. So... I may be wrong.
     
  27. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    Javascript prototype objects and C# class instances behave exactly the same on the basic level, same with CPP. All else is syntax sugar
     
  28. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    Ehhh, not exactly. Why do you think the === operator exists in javascript?

    Also, no they don't in C++.

    You can't even test equality of classes in C++ unless you explicitly define the operator.

    You can check if the pointers are equal... but that's technically checking if 2 ints are equal.

    Anyways, the nuances of language difference isn't my point. My point is that a greenthumb junior fresh out of a CS degree may not necessarily have your experience. Yet you found it fit to make fun of the complete stranger out of the blue as an adendum to making fun of the OP.

    Is this what you're doing?

    Are you really just habitually trying to defend that you're a dick and like to make fun of complete stangers that may not know as much as you?

    Whatever dude.

    Have fun with that.
     
  29. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    haha, you are fun at parties right, same in the thread about Tags,lighten up dude.

    We are only talking none value types here, yes javascript is a special case but reference types and value types are still treated the same as in C# and Cpp.

    edit: And no, I'm not making fun of anyone
     
  30. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    :shrugs:

    For sure brother.
     
  31. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    I was chatting with someone currently teaching Java/C# about this. They'd spent a lot of time looking at various textbooks, Lynda.com and whatever else. They pointed out that, around the country, students learned this in an informal way, like "You can use a function to change something, usually." You can memorize a few dozen simple rules and exceptions, and do pretty well.

    When you tell them they can toss all that patchwork stuff, and write better programs, if they learn just pointers and stack vs. heap; the sunk cost fallacy kicks in. In other words, they learned Reference Types so they didn't ever have to read a mouthful like "passing an implicit pointer by value."
     
    JoeStrout likes this.