• If you are citizen of an European Union member nation, you may not use this service unless you are at least 16 years old.

  • You already know Dokkio is an AI-powered assistant to organize & manage your digital files & messages. Very soon, Dokkio will support Outlook as well as One Drive. Check it out today!

View
 

Runtime-Copying Freezing and Comparing Objects

Page history last edited by Drew Hart 13 years, 4 months ago

Runtimes includes several standard mixins that you can use to implement some common design patterns such as copying, freezing, and comparing objects.  It is particularly important to learn how to use the copying and freezing patterns in SproutCore as they can lead to major performance improvements in your applications.

 

About Copying and Freezing

 

One of the biggest challenges in working with object oriented languages is differentiating between mutable and immutable objects.

 

Mutable objects (i.e. objects that can change state over time) are the default in JavaScript.  They are easy to work with because you can change them over time.  Because of this fact, mutable objects have some drawbacks:

 

  1. If you want to keep a reference to the object and be sure the state of the object won't change on you, you have to make a copy of it first.  This can add up to a lot of memory over time - particularly when passing around "structures" like rectangles, ranges, etc.
  2. It is much harder to keep track of when an object state has changed or not because you have to watch all properties on a mutable object, not just the object itself.

 

To solve this, SproutCore introduces two mixins that build on a feature that will be in the next version of JavaScript called freezing. Freezing an object simply means you are telling the system you no longer want to change it.  If any other part of your app tries to modify the object, it will throw an exception - allowing you to debug the issue.

 

In addition to debugging, frozen objects have the added benefit that you can safely keep a reference to them without having to worry about their state changing.  This reduces the amount of copies you need to make of an object, reducing your overall memory footprint.

 

Freezing Objects

 

To support freezing objects in SproutCore, you simply need to add the SC.Freezable mixin to your SC.Object subclass:

 

MyClass = SC.Object.extend(SC.Freezable, {

  // other properties...

}); 

 

Freezable objects have two new properties and one new method:

 

  • isFreezable is always YES.  You can use this property to check for the presence of the SC.Freezable mixin.
  • isFrozen is a boolean value that becomes YES when an object is frozen and NO otherwise.
  • freeze() is a method that will freeze the object if it has not already been frozen.  If the object is already frozen, this method does nothing.  freeze() also returns the receiver object itself so you can use it for chaining.

 

Once you have frozen an object, the set() method will no longer allow you to make changes to your object.  Your custom methods will still be able to make changes however.  In order to make your object truly freezable, you will need to make sure any methods that may change the state of your object check for the isFrozen property first:

 

MyClass = SC.Object.extend(SC.Freezable, {

  

  updateFoo: function(newFoo) {

    if (this.get('isFrozen')) throw SC.FROZEN_ERROR;

    // do rest of method here...

  }

 

});

  

Copying Objects

 

To add support for copying object, you should add the SC.Copyable mixin to your class definition.  SC.Copyable adds one property and two methods:

 

  • isCopyable is always YES.  You can use this to check for the presence of the Copyable mixin.  You can set this to NO to disable copying.
  • copy() - returns a new copy of the object.  The default implementation raises an exception.  You need to override this method yourself to support copying.
  • frozenCopy() - returns a new copy of the object and then freezes it.  If the object is already frozen, just returns itself.  Throws an exception if the object is not freezable.

 

Normally when you want to copy an object, you should just call copy().  You need to implement this method in your own subclasses as well to fully support this mixin.

 

If you get an object and want to make sure you have a copy that won't change, you can call frozenCopy() instead.  This normally works just like copy() except that it will freeze the returned object.  If the object is already frozen, this method won't make a copy; instead it will just return the object.  This way you can easily get copies of objects while keeping the actual memory allocation required to a minimum.

 

The example below shows how you might implement a freezable and copyable object:

 

MyClass = SC.Object.extend(SC.Freezable, SC.Copyable, {

 

  // properties we care about

  foo: null,

  bar: null,

 

  // sample method - make sure these always respect isFrozen!

  swap: function() {

    if (this.get('isFrozen')) throw SC.FROZEN_ERROR;

    var tmp = this.get('foo');

    this.set('foo', this.get('bar'));

    this.set('bar', tmp);

    return this;

  },

 

  // implement copy() to support copyable

  copy: function() {

    return this.constructor.create({

      foo: this.get('foo'),

      bar: this.get('bar')

    });

  }

});

 

var a = MyClass.create({ foo: "foo1", bar: "bar1" });

var b = a.copy();  // new instance of a

 

a.freeze()

var c = a.frozenCopy(); // returns a itself since it is already frozen

 

Comparing Objects

 

Normally you can compare any two objects in SproutCore using the SC.compare() method.  This method implements a standard set of comparisons between objects of different types a well as simple comparisons provided by JavaScript.  

 

When defining your own classes, however, it is not usually obvious how two objects should compare.  You can assist in this process by supporting the SC.Comparable mixin in your object.    SC.Comparable adds one property and one method to your class:

 

  • isComparable:  this property always returns YES, telling SproutCore your object supports the SC.Comparable mixin.
  • compare(): this method will be called to actually compare your object.  It will initially throw an exception.  You must override it with your own implementation.

 

Unlike most methods, compare() is actually called on your object constructor.  It will be passed two objects to compare; the first of which will be your class type.  You should implement this method to return -1 if the first parameters is less than the second, 1 if the second parameter is greater, or 0 if they are equal.  Do not reference "this" inside of the compare() function as it will not be called in a normal context.

 

Once you support this mixin, your object can be sorted against any other type of object any way that you choose.

 

Moving On

 

Get introduced to Key Value Coding »

or back to Runtime Programming Guide Home »

Comments (0)

You don't have permission to comment on this page.