{"id":92329,"date":"2019-04-19T18:21:00","date_gmt":"2019-04-19T18:21:00","guid":{"rendered":"http:\/\/www.gamasutra.com\/view\/news\/341123"},"modified":"2019-04-19T18:21:00","modified_gmt":"2019-04-19T18:21:00","slug":"blog-referencing-objectsa-names-vs-guids","status":"publish","type":"post","link":"https:\/\/sickgaming.net\/blog\/2019\/04\/19\/blog-referencing-objectsa-names-vs-guids\/","title":{"rendered":"Blog: Referencing objects\u00e2&#8364; &#8220;Names vs GUIDs"},"content":{"rendered":"<p>Here is the situation: You have created some sort of&nbsp;<a href=\"https:\/\/ourmachinery.com\/post\/the-story-behind-the-truth-designing-a-data-model\/\">data model<\/a>&nbsp;for representing objects in memory\/on disk. Now you need the ability for objects to refer to other objects. I.e., an object needs to talk&nbsp;<em>about<\/em>&nbsp;another object. Some examples:<\/p>\n<ul>\n<li>A material object may point to a texture object and say \u201cI want to use this as my diffuse map\u201d.<\/li>\n<li>An animation object may point to a model object and say \u201cI want to rotate this model around its z-axis\u201d.<\/li>\n<\/ul>\n<p>How can we accomplish this?<\/p>\n<p>Here are two options:<\/p>\n<ul>\n<li>\n<p><strong>Names:<\/strong>&nbsp;Each object is referred to by its&nbsp;<em>name.<\/em>&nbsp;The name is a string assigned to the object by the user and the user can change this string at will (rename the object).<\/p>\n<\/li>\n<li>\n<p><strong>GUIDs:<\/strong>&nbsp;Each object is referred to by a globally unique identifier (GUID). The GUID is assigned to the object on creation and never changes. It is guaranteed to only represent this particular object and no other.<\/p>\n<\/li>\n<\/ul>\n<p>Names are resolved in some kind of context (typically the children of the current object). Thus, to refer to an object that is \u201cfar away\u201d from us we might have to use a sequence of names to navigate the object tree, e.g.,&nbsp;<code>..\/..\/player\/head\/left_eye<\/code>. Much like a path in a file system, this sequence of names provides a&nbsp;<em>path<\/em>&nbsp;from one object in our object tree to another. Note that in this post I will sometimes somewhat sloppily talk about the&nbsp;<em>name<\/em>&nbsp;of an object when I actually mean the full path to an object.<\/p>\n<p>You might protest that there are other ways of representing references too. For example, an in-memory representation could just use a pointer. A disk representation could use a file offset. Combinations are possible too \u2014 for example (filename + offset) to represent an object inside a file. However, it is easy to become confused when considering the myriad of possibilities, so let\u2019s put all of that aside for the moment. In this post, I\u2019m going to focus on the difference between&nbsp;<em>names<\/em>&nbsp;and&nbsp;<em>GUIDs<\/em>&nbsp;and in the end we will see how the discussion applies to the other possibilities.<\/p>\n<blockquote>\n<p>Side note: There is another interesting option apart from names and GUIDs and that is to refer to an object by the hash of its content. With this approach, the same content is always referred to by the same unique identifier (its hash) and if you change the content all the references have to be updated. If you start to think about it, most of&nbsp;<a href=\"https:\/\/en.wikipedia.org\/wiki\/Git\">git<\/a>&nbsp;falls out as the result of this single design decision.<\/p>\n<\/blockquote>\n<p>Names and GUIDs both have their pros and cons, making it hard to say that one is strictly better than the other:<\/p>\n<table>\n<thead>\n<tr>\n<th><strong>Names<\/strong><\/th>\n<th><strong>IDs<\/strong><\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Fragile \u2014 if objects are renamed, moved or deleted, references will break<\/td>\n<td>Unreadable \u2014 references look like random numbers which makes them hard to debug<\/td>\n<\/tr>\n<tr>\n<td>Cumbersome \u2014 coming up with meaningful names for everything is a chore<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>Expensive \u2014 names have to be matched against the object tree to find the objects<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Each of these points can be argued back-and-forth endlessly. Can\u2019t we auto-assign names to make them easier to come up with? But how readable are names really if most of the things are just named&nbsp;<code>box_723<\/code>? Can\u2019t we make a tool that looks up a readable name from a GUID? Can\u2019t we also make a tool that automatically patches references when an object is renamed? Etc, etc, etc.<\/p>\n<p>Again, it\u2019s easy to get stuck in the nitty-gritty details of this and miss the bigger picture. To make things clearer, let\u2019s take a step back and ask ourselves:<\/p>\n<blockquote>\n<p>What is the fundamental difference between names and GUIDs?<\/p>\n<\/blockquote>\n<p>Think about it for a bit. Here\u2019s my answer:<\/p>\n<blockquote>\n<p>A GUID specifies an object identity, but a name specifies an object\u2019s role.<\/p>\n<\/blockquote>\n<p>The GUID&nbsp;<code>90e2294e-9daf-45f0-b75b-01fb85bb6dc8<\/code>&nbsp;always refers to one specific object \u2014 the one single object in the universe with that GUID. The path&nbsp;<code>head\/left_eye<\/code>&nbsp;refers to whatever object is currently acting as the character\u2019s left eye. It does not always have to be the same object. Maybe the character loses her eye at some point and it gets replaced with a glass eye. Maybe we can spawn multiple instances of the character in different configurations with different kinds of eyes \u2014 flesh eyes, robot eyes, anime eyes, etc. Regardless of the setup,&nbsp;<code>head\/left_eye<\/code>&nbsp;will refer to the character\u2019s left eye.<\/p>\n<p>In contrast, if we used a GUID to refer to the left eye and the eye got replaced, the GUID would still refer to the old eye we lost. And a single GUID couldn\u2019t be used to refer to different eyes in different character setups.<\/p>\n<table>\n<thead>\n<tr>\n<th>&nbsp;<\/th>\n<th><strong>Name<\/strong><\/th>\n<th><strong>GUID<\/strong><\/th>\n<th><strong>Hash<\/strong><\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>References objects by<\/strong><\/td>\n<td>Their role<\/td>\n<td>Their identity<\/td>\n<td>Their content<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The pointers and offsets that I talked about in the beginning of the post are similar to GUIDs, since they reference objects by identity. A pointer always points to the same object. In fact, you could see a pointer as a deserialized version of a GUID \u2014 a way of uniquely referencing an object in memory. Offsets too, uniquely identify objects. (But offsets are not permanent, so references must be updated each time a file is saved.)<\/p>\n<blockquote>\n<p>A name allows for \u201clate binding\u201d of references.<\/p>\n<\/blockquote>\n<p>To get from a name to an actual object, we need to&nbsp;<em>resolve<\/em>&nbsp;the name at some point. This involves matching the path against the object tree and finding the corresponding object. In contrast to a GUID, which always points to the same object, a name might resolve to different things at different points in time, or in different contexts. The reference isn\u2019t bound to a particular target until the name is resolved.<\/p>\n<p>When does this happen? You can decide that when you design a system based on your performance\/flexibility requirements. For example, you can decide to resolve all references once and only once \u2014 when the object is spawned. This is faster, because you only need to look references up once, but it also means that in the case where the eye is removed and replaced, the reference won\u2019t be updated to point to the new eye. So it\u2019s less flexible.<\/p>\n<p>The other option is to resolve the reference every single frame. This can handle objects being removed and\/or replaced, but it also means having to pay the performance cost of resolving the reference every single frame.<\/p>\n<p>With this new understanding of the fundamental difference between names and GUIDs we can take another look at the pros and cons we listed above and see if we can understand them better.<\/p>\n<p><strong>Names are fragile \u2014 they can break if objects are moved, renamed or deleted<\/strong><\/p>\n<p>Yes, this is the whole point!<\/p>\n<p>The main reason for using names is to allow late binding. Late binding means we don\u2019t know beforehand what the name will resolve to (or if it will resolve to anything at all). We can\u2019t get the benefits of late binding without also getting the drawbacks.<\/p>\n<p>For instance, in the example above, after the eye has been removed, but before it has been replaced with a glass eye,&nbsp;<code>head\/left_eye<\/code>&nbsp;will not resolve to anything \u2014 because the character doesn\u2019t have a left eye. Code that expects to find an object at&nbsp;<code>head\/left_eye<\/code>&nbsp;might break.<\/p>\n<p>A name might also resolve to&nbsp;<em>something unexpected<\/em>. For example, the eye might be removed and replaced by a little man. Code that was written to deal with an eye, or even with no eye, might break when it finds a little man in the eye socket.<\/p>\n<p>In addition to breaking in this correct way \u2014 where a resolve rightly fails because the object doesn\u2019t exist \u2014 references can also break in incorrect ways. The resolve might fail, not because there is no eye, but because the user made a mistake. For example, maybe the eye was named&nbsp;<code>LeftEye<\/code>&nbsp;instead of&nbsp;<code>left_eye<\/code>.<\/p>\n<p>To an extent \u2014 problems like this can be mitigated by good tooling. For example, the tools might warn about unresolved references. The tools might also assist with renaming, so that if you rename&nbsp;<code>left_eye<\/code>&nbsp;\u2192&nbsp;<code>LeftEye<\/code>&nbsp;all the references are updated to&nbsp;<code>LeftEye<\/code>&nbsp;too.<\/p>\n<p>But note that there is an inherent conflict here. The whole point of using names is to allow the references to be more lax and flexible. If the tools are too anal with their warnings it kind of defeats that purpose. For example, it might be totally correct that&nbsp;<code>head\/<\/code><code>halo<\/code>doesn\u2019t refer to anything, because the character starts out without a halo \u2014 she only gets that once she\u2019s completed the Holy Mission. If a tool spews out false positive warnings about things like this, users will soon learn to ignore them and miss the actually valuable warnings about real typos.<\/p>\n<p>Similarly, tools can\u2019t be too aggressive about updating references when objects are renamed either. Suppose that you designed a really cool robotic left eye for the character. Then you decide that it would look better as the right eye, so you move it into the right eye socket and rename it from&nbsp;<code>left_eye<\/code>&nbsp;to&nbsp;<code>right_eye<\/code>. If the references are auto-patched, all references to the left eye will now be changed to the right eye, which probably isn\u2019t correct. For example, if the&nbsp;<code>left_eyebrow<\/code>&nbsp;had a reference to its eye, and that reference was auto-patched, the&nbsp;<code>left_eyebrow<\/code>&nbsp;would now think it sits over the&nbsp;<code>right_eye<\/code>. On the other hand, some references could have meant \u201cthe robotic eye\u201d rather than \u201cthe eye in the left socket\u201d when they talked about&nbsp;<code>left_eye<\/code>&nbsp;and those references&nbsp;<em>should<\/em>&nbsp;get patched. Pretty messy and hard to make a nice UI for, although&nbsp;<a href=\"http:\/\/bitsquid.blogspot.com\/2010\/10\/dependency-checker.html\">I\u2019ve tried before<\/a>.<\/p>\n<p><strong>Names are cumbersome \u2014 coming up with meaningful names for everything is a chore<\/strong><\/p>\n<p>As discussed above, a&nbsp;<em>name<\/em>&nbsp;isn\u2019t just a string of characters, it is a description of a role, of a relationship.&nbsp;<code>head\/left_eye<\/code>&nbsp;means the left eye object in the head of the character. If you gave it a nonsensical name like&nbsp;<code>bob<\/code>&nbsp;or an auto-generated name like&nbsp;<code>Object_13<\/code>&nbsp;it wouldn\u2019t say anything about the role.<\/p>\n<p>To take advantage of the late binding feature of names you want to use meaningful names that match the concepts that you have in your game. I.e. if your characters can put on different helmets and backpacks you probably need&nbsp;<code>helmet<\/code>&nbsp;and&nbsp;<code>backpack<\/code>names. If helmets and backpacks are just visual features of some character models, can\u2019t be removed or swapped out and don\u2019t have any gameplay purpose, they might not need their own names, they might just be part of the&nbsp;<code>head<\/code>&nbsp;and&nbsp;<code>body<\/code>.<\/p>\n<p>You can think of this naming as sort of a \u201clogical rigging\u201d of the model.<\/p>\n<p>So yes, if you want to take advantage of late binding, you do have to spend some time coming up with meaningful names and hierarchies. If all your objects are just named&nbsp;<code>entity_2713<\/code>&nbsp;you are basically just using names as IDs. This has all the drawbacks of names (fragility, costly resolution) as well as all the drawbacks of IDs (unreadability). Don\u2019t do that.<\/p>\n<p><strong>Names are expensive \u2014 they have to be resolved<\/strong><\/p>\n<p>Again, late resolve is the point of using names, and it will always have a cost. You can\u2019t get the benefit of late resolve without paying the cost for it.<\/p>\n<p>Of course, it can be more or less costly, depending on how you implement it. My most important performance tip is: be clear about the scope in which names are resolved.<\/p>\n<p>I like to use fully qualified paths. I.e., referring to a character\u2019s left eye would be&nbsp;<code>head\/left_eye<\/code>. Referring to the left eye from the right eye would be&nbsp;<code>..\/left_eye<\/code>. Here,<code>..<\/code>&nbsp;goes up to the head and then&nbsp;<code>left_eye<\/code>&nbsp;descends to the right eye.<\/p>\n<p>It can be tempting to fall into the trap of convenience and say that we should be able to just use the name&nbsp;<code>left_eye<\/code>&nbsp;to refer to the left eye instead of a full path, but it has scary performance implications. Instead of just searching our children for a name match, we now have to search all our descendants recursively. And if we want this to work from the right eye too, we not only have to search all&nbsp;<em>our<\/em>&nbsp;descendants, we have to search all our&nbsp;<em>parent\u2019s descendants<\/em>&nbsp;too. Before you know it, you have to search the entire world for this&nbsp;<code>left_eye<\/code>. And even if we find it, how do we know it is the \u201cright one\u201d \u2014 the one the user meant? Maybe our helmet has a little statue on it, and maybe that statue has a&nbsp;<code>left_<\/code><code>eye<\/code>too? How do we make sure we don\u2019t find that one? Messy.<\/p>\n<p>My preferred implementation for resolving paths is to first hash each part of the path (this can be done offline), and then at each step, we match the hash at that step against the hashed names of the current object\u2019s children \u2014 either through a lookup table or directly. Maintaining a lookup table is probably only worth it once you start to have hundreds of children to match against.<\/p>\n<p>Even though this avoids really expensive stuff like searching the entire object tree or doing string comparison, it is still a lot more expensive than just following a pointer (which an ID deserializes into).<\/p>\n<h2 id=\"names-vs-guids-the-smackdown\">Names vs GUIDs \u2014 The Smackdown<\/h2>\n<p>With this deepened understanding \u2014 who wins, names or GUIDs?<\/p>\n<p>As discussed above, names have many disadvantages \u2014 they\u2019re fragile, cumbersome and costly. But they have two main advantages:<\/p>\n<ul>\n<li>\n<p>They express intent. When I refer to&nbsp;<code>head\/left_eye<\/code>&nbsp;it is clear to the reader what I&nbsp;<em>want<\/em>&nbsp;to refer to. Thus names have a&nbsp;<em>meaning<\/em>&nbsp;that pointers\/GUIDs don\u2019t have. Recording this meaning can be helpful. When we complain that identifiers are&nbsp;<em>unreadable<\/em>, it is the lack of&nbsp;<em>meaning<\/em>&nbsp;we talk about \u2014 not just the fact that the identifier is a jumble of hex characters. But meaning requires explicit intent. If your object is named&nbsp;<code>entity_23415<\/code>&nbsp;\u2014 there is no meaning in the name, it might just as well be called&nbsp;<code>cc1b9a7b-a5bb-4355-8cf1-f78b74fe2774<\/code>.<\/p>\n<\/li>\n<li>\n<p>They allow for \u201clate binding\u201d of the reference to an actual object. This allows new objects to \u201ctake the place\u201d\/\u201dfill the role\u201d of the originally referred object. Using this, we can \u201cpatch\u201d objects in lots of interesting way. For example, we can take a character, replace its eye with something else and all references to the eye will still work. To do this with GUIDs we need to patch up all references too, so that they point to the \u201cnew eye\u201d.<\/p>\n<\/li>\n<\/ul>\n<p>So which is best? It comes down to a judgment call.<\/p>\n<p>My take is this \u2014 we\u2019re trying to create a high-performance user-friendly game engine. Thus, we only want to pay the costs of using names (bad performance &amp; fragility) in the cases where we really take advantage of their strengths (intent &amp; late binding). In my experience \u2014 most of the times, we&nbsp;<em>don\u2019t need<\/em>&nbsp;these features. For example, when you are placing a bunch of trees in a level you don\u2019t really care about naming them and you don\u2019t have any need for something else \u201cassuming\u201d the role of one of those trees.<\/p>\n<p>For this reason,&nbsp;<em>The Machinery<\/em>&nbsp;uses GUIDs as the default way to represent references. When a model refers to a texture, it does so with a GUID. You can move or rename the texture and the model will still keep using the same texture until you explicitly point it to a different one.<\/p>\n<p>But in addition to this, we also explicitly allow for&nbsp;<em>name<\/em>&nbsp;references in some systems \u2014 systems that we think benefit from the extra flexibility:<\/p>\n<ul>\n<li>\n<p>Our visual scripting system has a \u201clookup entity by name\u201d node, allowing entities to be referred to semantically (such as&nbsp;<code>head\/left_eye<\/code>) from within the scripts.<\/p>\n<\/li>\n<li>\n<p>Our animation system is still under construction, but we plan to have a similar feature there, allowing animations to target loose and flexible things such as&nbsp;<code>helmet\/headlight\/color<\/code>.<\/p>\n<\/li>\n<\/ul>\n<p>Having two different \u201ckinds\u201d of references like this is in the engine by no means ideal. Whenever we are designing a system we have to ask ourselves: does this reference need the flexibility offered by names or is using a GUID OK? We are also possibly missing out on some flexibility \u2014 in the cases where we\u2019ve decided to use a GUID, it is much more cumbersome for the user to achieve the kind of dynamic retargeting that names make easy.<\/p>\n<p>Still, it seems like the best compromise to me \u2014 we get the performance and stability of GUIDs\/pointers in the majority of the code, but can still use the flexibility of names in the situations where we think it\u2019s needed.<\/p>\n<h2 id=\"see-also\">See also<\/h2>\n<ul>\n<li>\n<p>Pixar\u2019s&nbsp;<a href=\"https:\/\/graphics.pixar.com\/usd\/docs\/index.html#IntroductiontoUSD-Whatcan'tUSDdo?\">USD<\/a>&nbsp;format uses names for everything. From their viewpoint, having to occasionally fix broken references is worth the extra flexibility they get from using names everywhere. Of course, since they\u2019re not primarily targeting real-time rendering, their performance requirements are different.<\/p>\n<\/li>\n<li>\n<p>I\u2019ve&nbsp;<a href=\"http:\/\/bitsquid.blogspot.com\/2014\/06\/what-is-in-name.html\">written about this topic before<\/a>, if you want to see how my viewpoint has shifted over the years. Note though that the focus of that article is a little bit different. In that article I\u2019m talking about referencing assets\/resources on disk, so when I mention a&nbsp;<em>path<\/em>&nbsp;in that article I mean a&nbsp;<em>disk path<\/em>. Whereas, in this post, I\u2019m talking more about references in general and I\u2019m not that concerned with exactly how things get serialized to disk.<\/p>\n<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Here is the situation: You have created some sort of&nbsp;data model&nbsp;for representing objects in memory\/on disk. Now you need the ability for objects to refer to other objects. I.e., an object needs to talk&nbsp;about&nbsp;another object. Some examples: A material object may point to a texture object and say \u201cI want to use this as my [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":92330,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20],"tags":[],"class_list":["post-92329","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news"],"_links":{"self":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/92329","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/comments?post=92329"}],"version-history":[{"count":0,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/92329\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media\/92330"}],"wp:attachment":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media?parent=92329"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/categories?post=92329"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/tags?post=92329"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}