<commit_before>#+TITLE: ng-computed
#+AUTHOR: <NAME>
#+OPTIONS: toc:1

Computed properties for [[http://angularjs.org/][AngularJS]], à la [[http://knockoutjs.com/][Knockout JS]].

: bower install ng-computed


* Motivation

When writing applications within the AngularJS framework, it is often
necessary to compute values for scope properties which are dependent
on other scope values. AngularJS provides a basic mechanism to keep
these values up to date (~$watch~, and its variants), but these can
often become unwieldy as your dependencies become more complex or
dynamic.

This is the problem that =ng-computed= is aiming to solve. Within a
~$computed~ value's body it is not necessary to explicitly declare
what values you depend on, or when this value should be
re-evaluated. =ng-computed= will take care of all the details so you
can focus on your actual computation.

If you're not convinced that this is such a great idea, take a look at
[[#hello-world-example][the example below]]. If you're interested in how everything works, jump
down to [[#internals][our description of the internals]]. If you're just interested in
using =ng-computed= then [[#installation][installation is probably the best place to
start]].


#+NAME: #hello-world-example
* Hello World Example

#+BEGIN_SRC js
  angular.module('app', ['ngComputed', 'ng'])
      .controller('HelloWorldController', function($scope, $computed, $trackedEval) {
          angular.extend($scope, {$computed: $computed, $eval: $trackedEval});
          $scope.hello = "hello";
          $scope.world = "world";
          $scope.$computed("helloWorld", function() {
              return $scope.$eval("hello") + " " + $scope.$eval("world") + "!";
          });
      });
#+END_SRC

~$scope.helloWorld~ will be kept updated by the usual AngularJS watch
mechanisms, and it will be recalculated whenever the values of
~$scope.hello~ or ~$scope.world~ change.

For a more complete example, see [[#comparison-to-pure-angularjs][the comparative example below]].


#+NAME: #installation
* Installation

There are a few options for how to set up =ng-computed= in your
project. Throughout the documentation we're assuming you've opted for
/Globally Available/ and /Overriding Scope.$eval/.

** Globally available

We can add the ~$computed~ and ~$trackedEval~ methods at the
top-level of our application, on the ~Scope~ prototype. This makes
them readily available to any scopes, including isolate scopes. When
placing values on the ~Scope~ prototype we have another decision to
make: do we want to replace ~Scope.$eval~.

*** Overriding ~Scope.$eval~

The ~$trackedEval~ service gives you a drop-in replacement for
~Scope.$eval~, so we can replace ~Scope.$eval~ with ~$trackedEval~
without breaking anything.

#+BEGIN_SRC js
  angular.module('app', ['ngComputed', 'ng'])
      .run(function($rootScope, $trackedEval, $computed) {
          // we have to use the prototype, otherwise isolate scopes miss out
          angular.extend($rootScope.constructor.prototype, {
              $eval: $trackedEval,
              $computed: $computed
          });
      });
#+END_SRC

*** Not overriding ~Scope.$eval~

If you don't want to override ~Scope.$eval~ then you can choose a
different name instead. =ng-computed= makes no assumptions about what
names you use in your application.

#+BEGIN_SRC js
  angular.module('app', ['ngComputed', 'ng'])
      .run(function($rootScope, $trackedEval, $computed) {
          // we have to use the prototype, otherwise isolate scopes miss out
          angular.extend($rootScope.constructor.prototype, {
              getExpressionValue: $trackedEval,
              computedProperty: $computed
          });
      });
#+END_SRC

** Locally available

If you don't want to add ~$computed~ or ~$trackedEval~ to the ~Scope~
prototype then you can still use =ng-computed=. Within any scope you
can add ~$computed~ and ~$trackedEval~, using any names you desire,
and they will function normally.

#+BEGIN_SRC js
  angular.module('app', ['ngComputed', 'ng'])
      .controller('ExampleController', function($scope, $trackedEval, $computed) {
          $scope.$eval = $trackedEval;
          $scope.$computed = $computed;
      });
#+END_SRC

* Usage

Using =ng-computed= is quite simple. When you wish to create a
computed property, call ~$computed~ with the property's name (as a
string) and a specification of how to calculate the value (usually a
function, but see the section on [[#transformations][Transformations]] below). Based on the
specification, then, the value for the expressions is set.

Here is an example of a ~$computed~ property being set to a constant
value: ~10~.
#+BEGIN_SRC js
  $scope.$computed('computedExpression', function() {
      return 10;
  });
#+END_SRC

But setting constants isn't really interesting. We can already do
that. It's far more interesting to use ~$computed~ to calculate
values which depend on other things! In order to tell ~$computed~
about the dependency, we always retrieve values using ~$trackedEval~
(which, in our case, is available as ~$scope.$eval~):

#+BEGIN_SRC js
  $scope.firstName = "George";
  $scope.surname = "Clooney";
  $scope.$computed('fullName', function() {
      return $scope.eval('firstName')
          + " "
          + $scope.eval('surname');
  });
#+END_SRC

Now we have a value which will keep itself updated! If we modify
~$scope.firstName~ and ~$scope.surname~, ~$scope.fullName~ will be
updated as well.

** A small aside concerning purity

It's important to make sure that the specification that you provide to
~$computed~ is *almost [[https://en.wikipedia.org/wiki/Pure_function#Pure_expressions][pure]]*. What we mean by almost pure is that the
function must give the same result given the same arguments, but only
if you also consider the result of each ~$trackedEval~ invocation as
an additional (implicit) argument. Almost pure functions should also
have no side effects.

In our example from above, the function calculating ~$scope.fullName~
has no formal arguments (as is common for computed properties), but it
has two implicit arguments: ~$scope.firstName~ and
~$scope.surname~. Therefore when ~$scope.firstName~ changes we can
imagine our function being re-invoked with different arguments.

Specifications should be *almost pure* because they may be invoked at
unexpected times, or in unexpected ways. =ng-computed= makes no
guarantees about how many times a specification is invoked (although
an attempt is made to minimise the number of invocations).

** Extraction

When dealing with some types of data it's not possible to simply
return a simple value type from a specification. In cases like
asynchronous code it is often necessary to return some sort of a
promise object which will be eventually resolved elsewhere. As a help
for dealing with these cases, values returned by specifications
undergo /extraction/ before being used.

By default, extraction consists of either returning the value as-is,
or returning the value delivered by a ~$q~ promise. This extraction
process can be customised, as is discussed in [[#extractors][Extractors]].

An example of the default behaviour of ~$computed~:

#+BEGIN_SRC js
  $scope.url = "http://google.com";
  $scope.$computed('requestResult', function() {
      return $http.get($scope.$eval('url'));
  });
#+END_SRC

Here the value of ~$scope.requestResult~ will be set to the result of
fetching the URL specified in ~$scope.url~. As ~$scope.url~ changes,
new requests will be made and ~$scope.requestResult~ will be updated
accordingly.


#+NAME: #transformations
** Transformations

There are some occasions when calculating a value is a little bit more
involved than simply concatenating two strings looked up off the
scope. Sometimes a computation for a value is a clear, sequenced,
operation. In cases like this we can use /transformations/.

If ~$computed~ is given an array of functions as a specification, it
will run through each of them in sequence, calling each function with
the result of the previous one in the chain, and finally setting the
scope property to the result of the final function.

#+BEGIN_SRC js
  $scope.value = 10;
  $scope.$computed('valuePlusThree', [function() {
      return $scope.$eval('value');
  }, function(x) {
      return x+2;
  }, function(x) {
      return x+1;
  }]);
#+END_SRC

Here ~$scope.valuePlusThree~ is set to ~13~, and will continue to
update as ~value~ is updated. This example doesn't do anything that
we couldn't have done in one function, however. There's no reason why
we couldn't have used ~$scope.$eval('value') + 3~, so transformations
provide us with no benefit here.

Transformations do provide us with two advantages over simply calling
and composing functions, though:

1. Each function in a transformation has dependencies tracked
   separately

   This means that when a value changes, only the functions from that
   point down are re-evaluated (and even then, only if the preceding
   values have changed).

   #+BEGIN_SRC js
     $scope.a = 3;
     $scope.b = 5;
     $scope.c = 23;
     $scope.$computed('sumIsEven', [function() {
         return $scope.$eval('a') % 2; /* 1 */
     }, function(prev) {
         return (prev + $scope.$eval('b')) % 2; /* 2 */
     }, function(prev) {
         return (prev + $scope.$eval('c')) % 2; /* 3 */
     }, function(val) {
         return val == 0; /* 4 */
     }]);
   #+END_SRC

   In this case, ~$scope.sumIsEven~ will be set to true if the
   properties ~a~, ~b~ and ~c~ on ~$scope~ sum together to be an even
   number, and false otherwise. When any of ~a~, ~b~ or ~c~ chpfange
   then their step of the function is re-run. If the value has changed
   then the next step of the chain is invoked, and so on.

   If ~$scope.a~ were to be set to ~5~, the line marked as =1= would be
   re-run, but ~$scope.a~ would still be odd, and thus no further
   processing would take place.

   If ~$scope.b~ were to be set to ~6~ the line marked as =2= would be
   re-run, followed by =3=, then =4=. At the completion of line =4=
   ~$scope.sumIsEven~ would be set to ~false~.

   This automatic tracking and re-invocation of dependencies for
   separate steps in a computation can give significant performance
   benefits in some circumstances.

2. Each result in a transformation is extracted before being passed
   to the following function

   This means you can chain together asynchronous computations in a
   natural way:

   #+BEGIN_SRC js
     $scope.url = "http://google.com";
     $scope.$computed('uppercasePageContents', [function() {
         return $http.get($scope.$eval('url'));
     }, function(response) {
         return (response.data || "").toUpperCase(); // always shouting
     }]);
   #+END_SRC

Combining these two points can allow for complex calculations and
logic to be captured within a series of transformations while
=ng-computed= does all the work of making sure each step is re-run at
an appropriate time.

* Custom behaviour

** Watches

By default, ~$trackedEval~ tracks all dependencies as *deep equality*
watches. This can be quite inefficient, especially for dependencies
on large objects, so =ng-computed= provides two tools to help:

1. ~$watch~ batching

   Shipped along with =ng-computed= is a service called
   ~$batchedWatch~ which is a drop-in replacement for ~Scope.$watch~.
   ~$batchedWatch~ can be used as ~$watch~ on the ~Scope~ prototype,
   or on any individual scope, and will batch together separate watch
   functions on the same expression. This means that multiple deep
   watches on the same large object will incur only one ~angular.copy~
   / ~angular.equals~ per change.

   #+BEGIN_SRC js
     angular.module('app', ['ngComputed', 'ng'])
         .run(function($rootScope, $batchedWatch) {
             $rootScope.constructor.prototype.$watch = $batchedWatch;
         });
   #+END_SRC

2. ~$eval{Reference,Equal,Collection}~

   The ~$trackedEval~ service is not just a simple function. There
   are three variations of ~$trackedEval~ which each track the
   dependency as one of the varieties of watch:

   * ~$evalReference~, as a reference watch
   * ~$evalEqual~, as a deep equality watch
   * ~$evalCollection~, as a collection watch

   These can be placed on a scope and used as normal:

   #+BEGIN_SRC js
     angular.module('app', ['ngComputed', 'ng'])
         .controller('Example', function($scope, $trackedEval) {
             $scope.$evalReference = $trackedEval.$evalReference;
             $scope.$computed('computedValue', function() {
                 return $scope.$evalReference('shallowWatchedValue');
             });
         });
   #+END_SRC

   By default, ~$trackedEval~ is the ~$evalEqual~ function, but it
   can be configured using AngularJS's configuration mechanism:

   #+BEGIN_SRC js
     angular.module('app', ['ngComputed', 'ng'])
         .config(['$trackedEvalProvider', function($trackedEvalProvider) {
             $trackedEvalProvider.setDefaultWatchType('equal' /* or 'reference' or 'collection'*/);
         }]);
   #+END_SRC


#+NAME: #extractors
** Extractors

Often when a value is returned for a ~$computed~ property there is
some more work to be done: the value needs to be /extracted/ from some
sort of context. This may be from a asynchronous construct, such as a
promise, or from some other wrapper structure of your own devising. In
order to allow for easy use of such values, =ng-computed= has a
concept of an /extractor/.

An extractor is a function which is called to retrieve a value from a
container. The function is given the value returned to ~$computed~ and
a callback into which to deliver the value. The callback may be called
as many times as desired, and each time it is called it will continue
the evaluation of the ~$computed~ value (this may be simply setting it
on the scope, or may result in further computation [see
[[#transformations][Transformations]] for more details]).

** Long-lived specifications

One thing which would be nice to have, and which =ng-computed= makes
relatively easy, would be to be able to have function which don't
only depend on scope properties, but also depend on other external
data sources.

As an example, imagine that we had a ~DB~ service. This service
provides us with an interface to query an external database through a
~query~ method. ~query~ returns to us a "promise" which can be
resolved multiple times, and it ensures that it is continuously
resolved with the correct, most up-to-date, value until we call
~deregister~ on the result.

#+BEGIN_SRC js
  var result = DB.query("some query spec");
  // use result
  result.then(function(x){console.log("query result", x)});
  // the above may be run multiple times,
  // each time printing a new log line
  // until this next line
  result.deregister();
#+END_SRC

This type of an API can be easily wrapped to fit into an
=ng-computed= specification:

#+BEGIN_SRC js
  DB.query = function(fn) {
      var lastQuerySpec = null;
      var lastResult = null;
      return function() {
          var querySpec = fn.apply(this, arguments);
          if (angular.equals(querySpec, lastQuerySpec)) {
              return lastResult;
          } else {
              if (lastResult != null) {
                  lastResult.deregister();
                  lastResult = null;
              }
              lastQuerySpec = angular.copy(querySpec);
              return (lastResult = DB.query(querySpec));
          }
      };
  };
#+END_SRC

Now we can use this ~query~ function to wrap a function which returns
a query spec, which is then run on the database, returning the
promise to ~$computed~ to extract:

#+BEGIN_SRC js
  var deregister = $scope.$computed('databaseValuePlusOne', [
      DB.query(function() {
          return "some sort of query spec";
      }),
      function(x) { return x + 1; }
  ]);
#+END_SRC

This implementation, however, has a slight bug: when our computed
property's ~deregister~ function is called, or when ~$scope~ is
destroyed, it will leak the ~lastResult~ inside ~query~ without
deregistering it first.

In order to solve problems like this ~$computed~ will run the
~destroy~ property of a specification object, if it exists, when it is
deregistered. This gives a specification a hook to clean up anything
it may have allocated.

This means that it's easy to fix our ~query~ function above:

#+BEGIN_SRC js
    DB.query = function(fn) {
        var lastQuerySpec = null;
        var lastResult = null;
        var finalFunction = function() {
            var querySpec = fn.apply(this, arguments);
            if (angular.equals(querySpec, lastQuerySpec)) {
                return lastResult;
            } else {
                if (lastResult != null) {
                    lastResult.deregister();
                    lastResult = null;
                }
                lastQuerySpec = angular.copy(querySpec);
                return (lastResult = DB.query(querySpec));
            }
        };
        finalFunction.destroy = function() {
            if (lastResult != null)
                lastResult.deregister();
        };
        return finalFunction;
    };
#+END_SRC

Now when a ~query(...)~ specification is deregistered it will make
sure it also deregisters it's query, if it has one. This approach can
also work for poll-based systems, or any other long-lived resources.

*** Default configuration

By default, ~$computed~ will extract a value from a ~$q~ promise if
one is returned from the computed function.

#+BEGIN_SRC js
  $scope.$computed('extracted', function() {
      var deferred = $q.defer();
      deferred.resolve('a value'); // could happen later
      return deferred.promise;
  });
#+END_SRC

To serve as an example for custom extractors, this is how one would
specify the default extractor:

#+BEGIN_SRC js
  angular.module('app', ['ngComputed', 'ng'])
      .config(['$computedProvider', function($computedProvider) {
          $computedProvider.provideExtractor(['$q', function($q) {
              return function(value, callback) {
                  $q.when(value).then(callback, callback);
              };
          }]);
      }]);
#+END_SRC

This does not need to be done, however, as =ng-computed= will use
this extractor if no other extractor is specified.

*** Custom configuration

One possible form of an extractor will attempt to extract values from
"thunks". A thunk can be modelled as a function with zero arguments,
which must be invoked to retrieve the value it contains.

An extractor which dereferences thunks for ~$computed~ properties can
be easily implemented:

#+BEGIN_SRC js
  angular.module('app', ['ngComputed', 'ng'])
      .config(['$computedProvider', function($computedProvider) {
          $computedProvider.provideExtractor([function() {
              return function(value, callback) {
                  // because these are each called synchronously,
                  // they are already in a $digest cycle
                  if (angular.isFunction(value)) {
                      callback(value());
                  } else {
                      callback(value);
                  }
              };
          }]);
      }]);
#+END_SRC

If our application is configured with this extractor then the
following ~$computed~ property will be set to the value ~10~.

#+BEGIN_SRC js
  $scope.$computed('value', function() {
      return function(){return 10;};
  });
#+END_SRC

*** Asynchronous extractors

Asynchronous extractors have a few behaviours which may be unexpected,
and may have unintended consequences. These should be taken into
account when writing extractors for asynchronous results.

1. It is the extractor's responsibility to ensure that *any changes
   are processed after extraction*. The extractor may assume that it
   will have been invoked during the ~$apply~ or ~$digest~ phase.

   Essentially this means that whenever you are invoking ~callback~
   asynchronously you must ensure that it is run within a
   ~$rootScope.$apply~, or similar:

   #+BEGIN_SRC js
     $rootScope.$apply(function() {
         callback(value);
     });
   #+END_SRC

   This is usually not a problem when using AngularJS services (such
   as ~$q~ or ~$timeout~), but when using third-party promises or
   other callback mechanisms it can become an issue.

2. The ~callback~ provided to extractors is only valid until the
   function calculating ~value~ is invoked again. If the ~callback~
   is invoked after that time then it will have no effect.

   The intention behind this decision is to avoid the case where an
   earlier, but now irrelevant, promise being resolved overwrites a
   newer, relevant, promise's value. An example will hopefully make
   this clear:

   #+BEGIN_SRC js
     var deferredA = $q.defer(), deferredB = $q.defer();
     
     $scope.$apply(function() {
         $scope.useA = true;
         $scope.$computed('extractedValue', function() {
             if ($scope.$eval('useA'))
                 return deferredA.promise;
             else
                 return deferredB.promise;
         });
     });
     
     // we're now waiting for deferredA.promise
     
     $scope.$apply(function() {
         $scope.useA = false;
     });
     
     // now we've changed, and we want $scope.extractedValue
     // to take deferredB.promise's value
     
     $scope.$apply(function() {
         deferredB.resolve(100);
     });
     
     // Awesome! Now $scope.extractedValue ~~ 100
     
     $scope.$apply(function() {
         deferredA.resolve(0);
     });
     
     // Uh oh, now $scope.extractedValue ~~ 0
     // unless we've invalidated the old callback
   #+END_SRC


#+NAME: #debugging

* Debugging

TODO

<commit_msg>Woah, got the ordering *way* wrong!<commit_after>#+TITLE: ng-computed
#+AUTHOR: <NAME>
#+OPTIONS: toc:1

Computed properties for [[http://angularjs.org/][AngularJS]], à la [[http://knockoutjs.com/][Knockout JS]].

: bower install ng-computed


* Motivation

When writing applications within the AngularJS framework, it is often
necessary to compute values for scope properties which are dependent
on other scope values. AngularJS provides a basic mechanism to keep
these values up to date (~$watch~, and its variants), but these can
often become unwieldy as your dependencies become more complex or
dynamic.

This is the problem that =ng-computed= is aiming to solve. Within a
~$computed~ value's body it is not necessary to explicitly declare
what values you depend on, or when this value should be
re-evaluated. =ng-computed= will take care of all the details so you
can focus on your actual computation.

If you're not convinced that this is such a great idea, take a look at
[[#hello-world-example][the example below]]. If you're interested in how everything works, jump
down to [[#internals][our description of the internals]]. If you're just interested in
using =ng-computed= then [[#installation][installation is probably the best place to
start]].


#+NAME: #hello-world-example
* Hello World Example

#+BEGIN_SRC js
  angular.module('app', ['ngComputed', 'ng'])
      .controller('HelloWorldController', function($scope, $computed, $trackedEval) {
          angular.extend($scope, {$computed: $computed, $eval: $trackedEval});
          $scope.hello = "hello";
          $scope.world = "world";
          $scope.$computed("helloWorld", function() {
              return $scope.$eval("hello") + " " + $scope.$eval("world") + "!";
          });
      });
#+END_SRC

~$scope.helloWorld~ will be kept updated by the usual AngularJS watch
mechanisms, and it will be recalculated whenever the values of
~$scope.hello~ or ~$scope.world~ change.

For a more complete example, see [[#comparison-to-pure-angularjs][the comparative example below]].


#+NAME: #installation
* Installation

There are a few options for how to set up =ng-computed= in your
project. Throughout the documentation we're assuming you've opted for
/Globally Available/ and /Overriding Scope.$eval/.

** Globally available

We can add the ~$computed~ and ~$trackedEval~ methods at the
top-level of our application, on the ~Scope~ prototype. This makes
them readily available to any scopes, including isolate scopes. When
placing values on the ~Scope~ prototype we have another decision to
make: do we want to replace ~Scope.$eval~.

*** Overriding ~Scope.$eval~

The ~$trackedEval~ service gives you a drop-in replacement for
~Scope.$eval~, so we can replace ~Scope.$eval~ with ~$trackedEval~
without breaking anything.

#+BEGIN_SRC js
  angular.module('app', ['ngComputed', 'ng'])
      .run(function($rootScope, $trackedEval, $computed) {
          // we have to use the prototype, otherwise isolate scopes miss out
          angular.extend($rootScope.constructor.prototype, {
              $eval: $trackedEval,
              $computed: $computed
          });
      });
#+END_SRC

*** Not overriding ~Scope.$eval~

If you don't want to override ~Scope.$eval~ then you can choose a
different name instead. =ng-computed= makes no assumptions about what
names you use in your application.

#+BEGIN_SRC js
  angular.module('app', ['ngComputed', 'ng'])
      .run(function($rootScope, $trackedEval, $computed) {
          // we have to use the prototype, otherwise isolate scopes miss out
          angular.extend($rootScope.constructor.prototype, {
              getExpressionValue: $trackedEval,
              computedProperty: $computed
          });
      });
#+END_SRC

** Locally available

If you don't want to add ~$computed~ or ~$trackedEval~ to the ~Scope~
prototype then you can still use =ng-computed=. Within any scope you
can add ~$computed~ and ~$trackedEval~, using any names you desire,
and they will function normally.

#+BEGIN_SRC js
  angular.module('app', ['ngComputed', 'ng'])
      .controller('ExampleController', function($scope, $trackedEval, $computed) {
          $scope.$eval = $trackedEval;
          $scope.$computed = $computed;
      });
#+END_SRC

* Usage

Using =ng-computed= is quite simple. When you wish to create a
computed property, call ~$computed~ with the property's name (as a
string) and a specification of how to calculate the value (usually a
function, but see the section on [[#transformations][Transformations]] below). Based on the
specification, then, the value for the expressions is set.

Here is an example of a ~$computed~ property being set to a constant
value: ~10~.
#+BEGIN_SRC js
  $scope.$computed('computedExpression', function() {
      return 10;
  });
#+END_SRC

But setting constants isn't really interesting. We can already do
that. It's far more interesting to use ~$computed~ to calculate
values which depend on other things! In order to tell ~$computed~
about the dependency, we always retrieve values using ~$trackedEval~
(which, in our case, is available as ~$scope.$eval~):

#+BEGIN_SRC js
  $scope.firstName = "George";
  $scope.surname = "Clooney";
  $scope.$computed('fullName', function() {
      return $scope.eval('firstName')
          + " "
          + $scope.eval('surname');
  });
#+END_SRC

Now we have a value which will keep itself updated! If we modify
~$scope.firstName~ and ~$scope.surname~, ~$scope.fullName~ will be
updated as well.

** A small aside concerning purity

It's important to make sure that the specification that you provide to
~$computed~ is *almost [[https://en.wikipedia.org/wiki/Pure_function#Pure_expressions][pure]]*. What we mean by almost pure is that the
function must give the same result given the same arguments, but only
if you also consider the result of each ~$trackedEval~ invocation as
an additional (implicit) argument. Almost pure functions should also
have no side effects.

In our example from above, the function calculating ~$scope.fullName~
has no formal arguments (as is common for computed properties), but it
has two implicit arguments: ~$scope.firstName~ and
~$scope.surname~. Therefore when ~$scope.firstName~ changes we can
imagine our function being re-invoked with different arguments.

Specifications should be *almost pure* because they may be invoked at
unexpected times, or in unexpected ways. =ng-computed= makes no
guarantees about how many times a specification is invoked (although
an attempt is made to minimise the number of invocations).

** Extraction

When dealing with some types of data it's not possible to simply
return a simple value type from a specification. In cases like
asynchronous code it is often necessary to return some sort of a
promise object which will be eventually resolved elsewhere. As a help
for dealing with these cases, values returned by specifications
undergo /extraction/ before being used.

By default, extraction consists of either returning the value as-is,
or returning the value delivered by a ~$q~ promise. This extraction
process can be customised, as is discussed in [[#extractors][Extractors]].

An example of the default behaviour of ~$computed~:

#+BEGIN_SRC js
  $scope.url = "http://google.com";
  $scope.$computed('requestResult', function() {
      return $http.get($scope.$eval('url'));
  });
#+END_SRC

Here the value of ~$scope.requestResult~ will be set to the result of
fetching the URL specified in ~$scope.url~. As ~$scope.url~ changes,
new requests will be made and ~$scope.requestResult~ will be updated
accordingly.


#+NAME: #transformations
** Transformations

There are some occasions when calculating a value is a little bit more
involved than simply concatenating two strings looked up off the
scope. Sometimes a computation for a value is a clear, sequenced,
operation. In cases like this we can use /transformations/.

If ~$computed~ is given an array of functions as a specification, it
will run through each of them in sequence, calling each function with
the result of the previous one in the chain, and finally setting the
scope property to the result of the final function.

#+BEGIN_SRC js
  $scope.value = 10;
  $scope.$computed('valuePlusThree', [function() {
      return $scope.$eval('value');
  }, function(x) {
      return x+2;
  }, function(x) {
      return x+1;
  }]);
#+END_SRC

Here ~$scope.valuePlusThree~ is set to ~13~, and will continue to
update as ~value~ is updated. This example doesn't do anything that
we couldn't have done in one function, however. There's no reason why
we couldn't have used ~$scope.$eval('value') + 3~, so transformations
provide us with no benefit here.

Transformations do provide us with two advantages over simply calling
and composing functions, though:

1. Each function in a transformation has dependencies tracked
   separately

   This means that when a value changes, only the functions from that
   point down are re-evaluated (and even then, only if the preceding
   values have changed).

   #+BEGIN_SRC js
     $scope.a = 3;
     $scope.b = 5;
     $scope.c = 23;
     $scope.$computed('sumIsEven', [function() {
         return $scope.$eval('a') % 2; /* 1 */
     }, function(prev) {
         return (prev + $scope.$eval('b')) % 2; /* 2 */
     }, function(prev) {
         return (prev + $scope.$eval('c')) % 2; /* 3 */
     }, function(val) {
         return val == 0; /* 4 */
     }]);
   #+END_SRC

   In this case, ~$scope.sumIsEven~ will be set to true if the
   properties ~a~, ~b~ and ~c~ on ~$scope~ sum together to be an even
   number, and false otherwise. When any of ~a~, ~b~ or ~c~ chpfange
   then their step of the function is re-run. If the value has changed
   then the next step of the chain is invoked, and so on.

   If ~$scope.a~ were to be set to ~5~, the line marked as =1= would be
   re-run, but ~$scope.a~ would still be odd, and thus no further
   processing would take place.

   If ~$scope.b~ were to be set to ~6~ the line marked as =2= would be
   re-run, followed by =3=, then =4=. At the completion of line =4=
   ~$scope.sumIsEven~ would be set to ~false~.

   This automatic tracking and re-invocation of dependencies for
   separate steps in a computation can give significant performance
   benefits in some circumstances.

2. Each result in a transformation is extracted before being passed
   to the following function

   This means you can chain together asynchronous computations in a
   natural way:

   #+BEGIN_SRC js
     $scope.url = "http://google.com";
     $scope.$computed('uppercasePageContents', [function() {
         return $http.get($scope.$eval('url'));
     }, function(response) {
         return (response.data || "").toUpperCase(); // always shouting
     }]);
   #+END_SRC

Combining these two points can allow for complex calculations and
logic to be captured within a series of transformations while
=ng-computed= does all the work of making sure each step is re-run at
an appropriate time.

* Custom behaviour

** Watches

By default, ~$trackedEval~ tracks all dependencies as *deep equality*
watches. This can be quite inefficient, especially for dependencies
on large objects, so =ng-computed= provides two tools to help:

1. ~$watch~ batching

   Shipped along with =ng-computed= is a service called
   ~$batchedWatch~ which is a drop-in replacement for ~Scope.$watch~.
   ~$batchedWatch~ can be used as ~$watch~ on the ~Scope~ prototype,
   or on any individual scope, and will batch together separate watch
   functions on the same expression. This means that multiple deep
   watches on the same large object will incur only one ~angular.copy~
   / ~angular.equals~ per change.

   #+BEGIN_SRC js
     angular.module('app', ['ngComputed', 'ng'])
         .run(function($rootScope, $batchedWatch) {
             $rootScope.constructor.prototype.$watch = $batchedWatch;
         });
   #+END_SRC

2. ~$eval{Reference,Equal,Collection}~

   The ~$trackedEval~ service is not just a simple function. There
   are three variations of ~$trackedEval~ which each track the
   dependency as one of the varieties of watch:

   * ~$evalReference~, as a reference watch
   * ~$evalEqual~, as a deep equality watch
   * ~$evalCollection~, as a collection watch

   These can be placed on a scope and used as normal:

   #+BEGIN_SRC js
     angular.module('app', ['ngComputed', 'ng'])
         .controller('Example', function($scope, $trackedEval) {
             $scope.$evalReference = $trackedEval.$evalReference;
             $scope.$computed('computedValue', function() {
                 return $scope.$evalReference('shallowWatchedValue');
             });
         });
   #+END_SRC

   By default, ~$trackedEval~ is the ~$evalEqual~ function, but it
   can be configured using AngularJS's configuration mechanism:

   #+BEGIN_SRC js
     angular.module('app', ['ngComputed', 'ng'])
         .config(['$trackedEvalProvider', function($trackedEvalProvider) {
             $trackedEvalProvider.setDefaultWatchType('equal' /* or 'reference' or 'collection'*/);
         }]);
   #+END_SRC


#+NAME: #extractors
** Extractors

Often when a value is returned for a ~$computed~ property there is
some more work to be done: the value needs to be /extracted/ from some
sort of context. This may be from a asynchronous construct, such as a
promise, or from some other wrapper structure of your own devising. In
order to allow for easy use of such values, =ng-computed= has a
concept of an /extractor/.

An extractor is a function which is called to retrieve a value from a
container. The function is given the value returned to ~$computed~ and
a callback into which to deliver the value. The callback may be called
as many times as desired, and each time it is called it will continue
the evaluation of the ~$computed~ value (this may be simply setting it
on the scope, or may result in further computation [see
[[#transformations][Transformations]] for more details]).

*** Default configuration

By default, ~$computed~ will extract a value from a ~$q~ promise if
one is returned from the computed function.

#+BEGIN_SRC js
  $scope.$computed('extracted', function() {
      var deferred = $q.defer();
      deferred.resolve('a value'); // could happen later
      return deferred.promise;
  });
#+END_SRC

To serve as an example for custom extractors, this is how one would
specify the default extractor:

#+BEGIN_SRC js
  angular.module('app', ['ngComputed', 'ng'])
      .config(['$computedProvider', function($computedProvider) {
          $computedProvider.provideExtractor(['$q', function($q) {
              return function(value, callback) {
                  $q.when(value).then(callback, callback);
              };
          }]);
      }]);
#+END_SRC

This does not need to be done, however, as =ng-computed= will use
this extractor if no other extractor is specified.

*** Custom configuration

One possible form of an extractor will attempt to extract values from
"thunks". A thunk can be modelled as a function with zero arguments,
which must be invoked to retrieve the value it contains.

An extractor which dereferences thunks for ~$computed~ properties can
be easily implemented:

#+BEGIN_SRC js
  angular.module('app', ['ngComputed', 'ng'])
      .config(['$computedProvider', function($computedProvider) {
          $computedProvider.provideExtractor([function() {
              return function(value, callback) {
                  // because these are each called synchronously,
                  // they are already in a $digest cycle
                  if (angular.isFunction(value)) {
                      callback(value());
                  } else {
                      callback(value);
                  }
              };
          }]);
      }]);
#+END_SRC

If our application is configured with this extractor then the
following ~$computed~ property will be set to the value ~10~.

#+BEGIN_SRC js
  $scope.$computed('value', function() {
      return function(){return 10;};
  });
#+END_SRC

*** Asynchronous extractors

Asynchronous extractors have a few behaviours which may be unexpected,
and may have unintended consequences. These should be taken into
account when writing extractors for asynchronous results.

1. It is the extractor's responsibility to ensure that *any changes
   are processed after extraction*. The extractor may assume that it
   will have been invoked during the ~$apply~ or ~$digest~ phase.

   Essentially this means that whenever you are invoking ~callback~
   asynchronously you must ensure that it is run within a
   ~$rootScope.$apply~, or similar:

   #+BEGIN_SRC js
     $rootScope.$apply(function() {
         callback(value);
     });
   #+END_SRC

   This is usually not a problem when using AngularJS services (such
   as ~$q~ or ~$timeout~), but when using third-party promises or
   other callback mechanisms it can become an issue.

2. The ~callback~ provided to extractors is only valid until the
   function calculating ~value~ is invoked again. If the ~callback~
   is invoked after that time then it will have no effect.

   The intention behind this decision is to avoid the case where an
   earlier, but now irrelevant, promise being resolved overwrites a
   newer, relevant, promise's value. An example will hopefully make
   this clear:

   #+BEGIN_SRC js
     var deferredA = $q.defer(), deferredB = $q.defer();
     
     $scope.$apply(function() {
         $scope.useA = true;
         $scope.$computed('extractedValue', function() {
             if ($scope.$eval('useA'))
                 return deferredA.promise;
             else
                 return deferredB.promise;
         });
     });
     
     // we're now waiting for deferredA.promise
     
     $scope.$apply(function() {
         $scope.useA = false;
     });
     
     // now we've changed, and we want $scope.extractedValue
     // to take deferredB.promise's value
     
     $scope.$apply(function() {
         deferredB.resolve(100);
     });
     
     // Awesome! Now $scope.extractedValue ~~ 100
     
     $scope.$apply(function() {
         deferredA.resolve(0);
     });
     
     // Uh oh, now $scope.extractedValue ~~ 0
     // unless we've invalidated the old callback
   #+END_SRC

** Long-lived specifications

One thing which would be nice to have, and which =ng-computed= makes
relatively easy, would be to be able to have function which don't
only depend on scope properties, but also depend on other external
data sources.

As an example, imagine that we had a ~DB~ service. This service
provides us with an interface to query an external database through a
~query~ method. ~query~ returns to us a "promise" which can be
resolved multiple times, and it ensures that it is continuously
resolved with the correct, most up-to-date, value until we call
~deregister~ on the result.

#+BEGIN_SRC js
  var result = DB.query("some query spec");
  // use result
  result.then(function(x){console.log("query result", x)});
  // the above may be run multiple times,
  // each time printing a new log line
  // until this next line
  result.deregister();
#+END_SRC

This type of an API can be easily wrapped to fit into an
=ng-computed= specification:

#+BEGIN_SRC js
  DB.query = function(fn) {
      var lastQuerySpec = null;
      var lastResult = null;
      return function() {
          var querySpec = fn.apply(this, arguments);
          if (angular.equals(querySpec, lastQuerySpec)) {
              return lastResult;
          } else {
              if (lastResult != null) {
                  lastResult.deregister();
                  lastResult = null;
              }
              lastQuerySpec = angular.copy(querySpec);
              return (lastResult = DB.query(querySpec));
          }
      };
  };
#+END_SRC

Now we can use this ~query~ function to wrap a function which returns
a query spec, which is then run on the database, returning the
promise to ~$computed~ to extract:

#+BEGIN_SRC js
  var deregister = $scope.$computed('databaseValuePlusOne', [
      DB.query(function() {
          return "some sort of query spec";
      }),
      function(x) { return x + 1; }
  ]);
#+END_SRC

This implementation, however, has a slight bug: when our computed
property's ~deregister~ function is called, or when ~$scope~ is
destroyed, it will leak the ~lastResult~ inside ~query~ without
deregistering it first.

In order to solve problems like this ~$computed~ will run the
~destroy~ property of a specification object, if it exists, when it is
deregistered. This gives a specification a hook to clean up anything
it may have allocated.

This means that it's easy to fix our ~query~ function above:

#+BEGIN_SRC js
    DB.query = function(fn) {
        var lastQuerySpec = null;
        var lastResult = null;
        var finalFunction = function() {
            var querySpec = fn.apply(this, arguments);
            if (angular.equals(querySpec, lastQuerySpec)) {
                return lastResult;
            } else {
                if (lastResult != null) {
                    lastResult.deregister();
                    lastResult = null;
                }
                lastQuerySpec = angular.copy(querySpec);
                return (lastResult = DB.query(querySpec));
            }
        };
        finalFunction.destroy = function() {
            if (lastResult != null)
                lastResult.deregister();
        };
        return finalFunction;
    };
#+END_SRC

Now when a ~query(...)~ specification is deregistered it will make
sure it also deregisters it's query, if it has one. This approach can
also work for poll-based systems, or any other long-lived resources.

#+NAME: #debugging
* Debugging

TODO


{'fraction_non_alphanumeric': 0.09759918897746647, 'fraction_numerical': 0.0023040412884198884, 'mean_word_length': 3.264393790528591, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '63439', 'n_tokens_mistral': 12284, 'n_tokens_neox': 11777, 'n_words': 5095}