When your high school gym teacher asked you to "drop and give me 20", did you ever have the guts to ask, "20 what?" Being the geeks that we are, such a question is perfectly valid, although in asking you might just earn yourself another 20 units of unwanted exercise! Although assumptions can be made in the real world about the unit implied by a certain context, the same can't be said for our code. Compilers and interpreters usually can't make assumptions like the one above based on context.
Every programming language supports numbers natively, although they are almost always implemented as primitive types – a place in memory to store a number, nothing less, nothing more. But as the opening paragraph suggests, numbers by themselves present very little information, unless they are paired with a unit. We write our own code to deal with units, but most often the code is not consistent, both in checking the unit of a number, and converting to and from units.
If you are developing in a dynamic language, such as JavaScript, you are offered an opportunity to enhance the way numbers are stored natively. The ability to "attach" a unit to a number can be gifted to the Number data type. In the case of JavaScript, this is possible because a Number is an object, and most objects can be modified through JavaScripts prototype language feature.
Enhancing the Number object with the prototype property:
Number.prototype.setUnit = function(unit) {
this._unit = unit;
}
Number.prototype.getUnit = function() {
return this.unit;
}
The downside is that to leverage these new functions, we need to "formally" create a number object:
myNum = new Number(56);
myNum.setUnit('inches');
console.log( myNum.getUnit() );
On the flip-side, we still get to use our number as we're used to, it's functionally the same:
myNum + 50
is still a valid arithmetic operation. The internal value of myNum is still 56.
Adjusting the constructor for more meaningful code
Sure, the technique above works great, but who really wants to initialize a Number object that way every time they want need to use an integer or float? What if we adjusted the Number object's constructor, to allow us to provide the unit as well? That would certainly make our additional efforts of creating a Number object more worthwhile, and perhaps make the code a little easier on the eyes:
var oldProto = Number.prototype;
Number = function(num, unit) {
this.value = num;
this.unit = unit;
};
oldProto.valueOf = function() { return this.value }
Number.prototype = oldProto;
Number.prototype.setUnit = function(unit) {
this.unit = unit;
}
Number.prototype.getUnit = function() {
return this.unit;
}
The real magic of the code above is the recreation of the valueOf() function on the Number object. If you've read an opinions on creating numbers with the new keyword, you might have found them all to be against such a practice. But, much of their reasoning is that you loose the ability to perform operations on them. By redefining the valueOf function that JavaScript uses internally, we preserve that capability.
However, it should be noted that the equality operation will no longer work! This is important to remember.
x = new Number(30, 'inches');
y = new Number(30, 'inches');
x == y
will return false. This is because the equality operator does an object comparison and does not use the valueOf() function. I'd have to say that this is probably the only downside to this method, we're forced to compare against the valueOf() method:
x.valueOf() == y.valueOf();
Or, if we're feeling ambitious, adding a equals function to the Number object would serve our purposes equally well:
x.equals(y);
If you think this approach lends to code that's easier to read and write, using the code examples above, creating such a function should be relatively easy.
1 Comment