18

I'm going through Immutable.js's source code and there's an ownerID field that I don't understand.

Here's the source for Map.asMutable() and Map.asImmutable(): https://github.com/facebook/immutable-js/blob/master/src/Map.js#L171

It seems like the only difference between a mutable and an immutable object are their ownerIDs. What is an ownerID and what is it used for?

Leo Jiang
  • 24,497
  • 49
  • 154
  • 284
  • None of the answer give a clear explanation, here's my current understanding: `ownerID` is basically `isMutable`. However, they need a way to compare mutable objects for whatever reason, so they need an unique identifier for each object. `isMutable` implies it's a boolean, so they named it `ownerID`. It could be renamed `mutableObjectID`. – Leo Jiang Mar 30 '16 at 18:55
  • If you look at the last part of my answer below, you'll see that what their code is doing (I think) is checking if the object has mutated by checking if the `ownerID` has changed. If it has mutated, they return a new object. If it hasn't mutated or the `ownerId` doesn't exist, they just return the current object since there is no reason to make a new one. – Matthew Herbst Mar 31 '16 at 06:26
  • Isn't that what `__altered` is for? It seems like they have to compare objects with other objects as well. I don't know why though. – Leo Jiang Mar 31 '16 at 07:13

3 Answers3

4

If you track back the property:

L#14:

import { DELETE, SHIFT, SIZE, MASK, NOT_SET, CHANGE_LENGTH, DID_ALTER, OwnerID,
          MakeRef, SetRef, arrCopy } from './TrieUtils'

in src/TrieUtils.js :

L#36:

// A function which returns a value representing an "owner" for transient writes
// to tries. The return value will only ever equal itself, and will not equal
// the return of any subsequent call of this function.
export function OwnerID() {}

It is some property they create like hash to represent a virtual owner.

ProllyGeek
  • 15,517
  • 9
  • 53
  • 72
  • 1
    I get that `new OwnerID` is basically `Symbol()`. What does a virtual owner mean and how does that relate to immutability? – Leo Jiang Mar 24 '16 at 06:47
  • @Linksku adding ID as a property is like creating a unique hash, but they call it owner, you may have 2 same identical objects with different hashes, this means that they are not the same object, this doesn't relate to immutability, and neither your question relates to immutability, you just wanted to know what is that OwnerID, correct ? – ProllyGeek Mar 24 '16 at 08:23
  • 1
    It relates to immutability because the only difference between a mutable and immutable object in ImmutableJS is the `ownerID` property. I want to understand why they added this property and what it's for. – Leo Jiang Mar 30 '16 at 18:47
  • 1
    This answer isn't actually helpful – notrota Apr 21 '18 at 04:31
3

It is used to ensure mutability in asMutable returned instances. When asMutable is invoked, it ensures an __ownerId and returns the current instance back -

asMutable() {
    return this.__ownerID ? this : this.__ensureOwner(new OwnerID());
}

Then any supported mutating operations return the current instance back, instead of creating a new instance with the changes (which is key for immutability).

E.g., here's how the "clear" method operates based on the presence of __ownerId -

clear() {
    if (this.size === 0) {
      return this;
    }
    if (this.__ownerID) {
      this.size = 0;
      this._root = null;
      this.__hash = undefined;
      this.__altered = true;
      return this;
    }
    return emptyMap();
}

Notice that when this.__ownerID is present, the method returns the current instance (thereby mutating itself). But when it is absent, it returns a new map for ensuring immutability.

Matthew Herbst
  • 29,477
  • 23
  • 85
  • 128
hazardous
  • 10,627
  • 2
  • 40
  • 52
1

From the source code:

// A function which returns a value representing an "owner" for transient writes
// to tries. The return value will only ever equal itself, and will not equal
// the return of any subsequent call of this function.
function OwnerID() {}

My understanding of the above is that the this.__ownerID field is used to compare objects. A Map being compared against itself will have the same ownerID, while a Map being compared against another Map will see two different ownerIDs.

You can see an example of this usage a little farther down in the file in question:

__ensureOwner(ownerID) {
  if (ownerID === this.__ownerID) {
    return this;
  }
  if (!ownerID) {
    this.__ownerID = ownerID;
    this.__altered = false;
    return this;
  }
  return makeMap(this.size, this._root, ownerID, this.__hash);
}

In fact, searching the entire repo, you'll see that this function is common across data types, with each type having a slightly modified version to return a correct new version of that type.

Matthew Herbst
  • 29,477
  • 23
  • 85
  • 128