-
Notifications
You must be signed in to change notification settings - Fork 168
API Overview
The API we're hoping to get to; code doesn't look like this at present. Progress is happening in the abstract-structures branch.
The code is broken into three top-level namespaces:
-
types: holds all the data types used by numbers, including things like Matrix, Vector, Set, Sample, Point, Function, etc. This namespace is broken into sub namespaces for each branch of the type hierarchy. E.g. if Matrix is one of the root types, then there will be a namespace
numbers.types.matrix
, on which the Matrix type will live (i.e.numbers.types.matrix.Matrix
), along with its sub-types (e.g.numbers.types.matrix.Vector
). -
core: holds any method that must be used by more than one numbers.js data type, so that none of the types have to be dependent on one another. Most data structures will be dependent on core, but its only dependency is
util
(see below). In addition to holding methods common across types,core
holds numbers-related methods that don't belong on a type for whatever reason (e.g. the methods related to primes, because putting them on an integer type would be too unwieldy.) -
util: holds generic js extensions/patches that don't have anything to do with numbers per se (e.g. cross-browser patches for key methods or simple functions for determining the type of an arg).
Although the code is organized in these three namespaces, many of these methods are available directly on the numbers object. Specifically, all methods in core
and util
are aliased there, such that numbers.core.methodX
is equivalent to numbers.methodX
and numbers.util.methodY
is equivalent to numbers.methodY
. The constructors for the numbers data types are also exposed on the numbers
object through 'createTypeName' methods, e.g. new numbers.types.matrix.Matrix
is equivalent to simply calling numbers.createMatrix
.
While the numbers.js methods will be divided between the types and core
, the documentation could be make it easier for developers to get started with the library if it was still organized by mathematical domain (calc, stats, etc.). To that end, the example files should continue to be organized this way (i.e. one for each domain). In addition, methods in each type and in core should be tagged in their docblock with the field they're relevant to.
-
to[TypeName] and toMember methods
Most types will have ato[TypeName]()
method that takes an argument and returns it unchanged if it's already of the given numbers.js type, tries to convert it to that type from a built in javascript type where possible, and returns false otherwise. This offers an easy way for instance methods to support native js data structures and do type checking at the same time. E.g. fromSet
:Set.toSet = function(arg) { return Set.isSet(arg) ? arg : (numbers.util.isArray(arg) ? Set(arg) : false); } //from the Set "class" function union(B) { if ((B = Set.toSet(B)) === false) { throw new Error("B must be a set or an array."); } //... }; //So setA.union([1,3,5]); //works, as opposed to setA.union(numbers.createSet([1,3,5])) setA.union(setB); //works setB.union("bob"); //throws an error
toMember()
methods, which should be defined on types that are collections (Sets, Samples, Matrices), serve a similar role. E.g.://from the Set "class" function add(member) { if((member = Set.toMember(member)) === false) { throw new Error("Element you're trying to add is not a valid member."); } //... }
-
isType methods All types have an
isType
method that takes an arg and determines whether it's of the type in question, first by checking theconstructor
property and then by falling back to duck-typing (i.e. checking for the existence of a set of required methods). -
Some types extend
Array
Extending native javascript arrays where possible helps numbers achieve more-seamless interoperability with other libraries (e.g. if numbers has aSample
object that extendsArray
, that object can be passed straight to d3 for graphing or jQuery for listing in a table.). ExtendingArray
also lowers the learning curve, because all the ways for working with native arrays that js developers are used to (e.g. iterating them withfor
loops) will continue to work.Unfortunately, extending
Array
in javascript is a mess, but it can be done workably by having an object constructor that just returns a native array with methods tacked onto it directly ("parasitic inheritance" in Crockford-ese). And this can even be performant if the constructor tacks on functions which are only instantiated once in an outside scope and then simply referenced by the returned array's properties. So this is what numbers does.The one side effect of this parasitic inheritance is that it means numbers types that extend
Array
have non-numeric,ownProperty
s that are not found on Array by default (i.e. one for each method, as the methods are added to the array directly, rather than to the prototype). Normally, this won't cause any conflicts with other libraries, as loops that read array data typically don't iterate over non-numeric properties. However, for the rare cases that a conflict occurs, all the types extendingArray
have atoPlainArray
method that removes all these numbers methods and other instance vars, so that the object is really indistinguishable from an untouchedArray
.Implementing parasitic inheritance and
toPlainArray
, along withis[Type]
on theseArray
sub-types, is made easier by functions innumbers.util
that handle the generic logic.