Pages

Wednesday, September 28, 2016

Concrete Point No. 3

A series of posts beginning with An Abstract Point present hierarchies of JavaScript and Java code snippets (classes) used to model the concept of a point in the context of Euclidean geometry. In this post we simplify matters by looking at examples of JavaScript and Java code snippets that model a point in three-dimensional space but are not part of a class hierarchy.

JavaScript constructors used to produce objects of type PointInSpace


JavaScript functions may be used to produce instances of objects of a particular type or class by preceding an invocation of the function with the keyword new. JavaScript functions used this way are called constructors. For example, given the following function called PointInSpace, the statement new PointInSpace(1, 2, 3) produces an instance of an object with various properties including the properties x, y, z, and distanceFromOrigin.
function PointInSpace(x, y, z) {
  this.x = x;
  this.y = y;
  this.z = z;
  this.distanceFromOrigin = function() {
    return Math.sqrt(
      Math.pow(this.x, 2) +
      Math.pow(this.y, 2) +
      Math.pow(this.z, 2));
  }
};

When used as a constructor, a function creates an instance of an object that also has a property called __proto__. The value of a newly created object's __proto__ property defaults to the value of Object.prototype, which is a special object that always exists.

On pages 199 and 200 of JavaScript: The Definitive Guide (6th edition), David Flannagan explains that two objects that “inherit properties from the same prototype” are members of the same class. To create a new class of objects, we define a prototype object as a property of a constructor. Then objects created using the constructor will have their __proto__ properties initially set to the value of the constructor's prototype property instead of the default value, Object.prototype. For example:
function PointInSpace(x, y, z) {
  this.x = x;
  this.y = y;
  this.z = z;
};
PointInSpace.prototype = {
  distanceFromOrigin: function() {
    return Math.sqrt(
      Math.pow(this.x, 2) +
      Math.pow(this.y, 2) +
      Math.pow(this.z, 2));
  }
};

In both of the cases shown above, if we create an instance of an object (e.g. var p = new PointInSpace(1,2,3);) then we can invoke the method distanceFromOrigin using syntax that might suggest that the method is a direct property of the object (e.g. p.distanceFromOrigin();). But in fact, distanceFromOrigin may be a property of the object or it may be a property of the object's __proto__ object. Or it may be a property of some __proto__ object nested any number of layers beneath the object's __proto__ object!

When searching for a property to evaluate, a JavaScript interpreter first looks to see whether the property name in question identifies a property of the object. If such a property is found, JavaScript evaluates it and returns the result. Otherwise, JavaScript looks for the property in the object's __proto__ object. If found there, JavaScript returns the result of evaluating the property. Otherwise, JavaScript continues the search, looking in the __proto__ object of the object's __proto__ object (if the object exists) and so on until either a matching property is found or no more nested __proto__ objects are found.

Note that when defining a prototype object for a given constructor, we might want to set the constructor property of the prototype object so that it refers back to the constructor function itself. For example:
function PointInSpace(x, y, z) {
  this.x = x;
  this.y = y;
  this.z = z;
};
PointInSpace.prototype = {
  distanceFromOrigin: function() {
    return Math.sqrt(
      Math.pow(this.x, 2) +
      Math.pow(this.y, 2) +
      Math.pow(this.z, 2));
  }
};
PointInSpace.prototype.constructor = PointInSpace;

A Java class used to produce objects of type PointInSpace


VoilĂ :
class PointInSpace {
  double x;
  double y;
  double z;
  PointInSpace(double x, double y, double z) {
    this.x = x;
    this.y = y;
    this.z = z;
  }
  double distanceFromOrigin() {
    return Math.sqrt(
      Math.pow(this.x, 2) +
      Math.pow(this.y, 2) +
      Math.pow(this.z, 2));
  }
}

class TestPoint {
  public static void main(String[] args) {
    PointInSpace p1 = new PointInSpace(1, 2, 3);
    System.out.println(p1.distanceFromOrigin());
  }
}