Javascript: How to ensure that a parameter has a specific interface? - javascript

Edit: I found this interesting library which looks like it can do exactly what I was describing at the bottom: https://github.com/philbooth/check-types.js
Looks like you can do it by calling check.quacksLike.
I'm fairly new to using javascript and I'm loving the amount of power it offers, but sometimes it is too flexible for my sanity to handle. I would like an easy way to enforce that some argument honors a specific interface.
Here's a simple example method that highlights my problem:
var execute = function(args)
{
executor.execute(args);
}
Let's say that the executor expects args to have a property called cmd. If it is not defined, an error might be caught at another level when the program tries to reference cmd but it is undefined. Such an error would be more annoying to debug than explicitly enforcing cmd's existence in this method. The executor might even expect that args has a function called getExecutionContext() which gets passed around a bit. I could imagine much more complex scenarios where debugging would quickly become a nightmare of tracing through function calls to see where an argument was first passed in.
Neither do I want to do something on the lines of:
var execute = function(args)
{
if(args.cmd === undefined || args.getExecutionContext === undefined ||
typeof args.getExecutionContext !== 'function')
throw new Error("args not setup correctly");
executor.execute(args);
}
This would entail a significant amount of maintenance for every function that has arguments, especially for complex arguments. I would much rather be able to specify an interface and somehow enforce a contract that tells javascript that I expect input matching this interface.
Maybe something like:
var baseCommand =
{
cmd: '',
getExecutionContext: function(){}
};
var execute = function(args)
{
enforce(args, baseCommand); //throws an error if args does not honor
//baseCommand's properties
executor.execute(args);
}
I could then reuse these interfaces amongst my different functions and define objects that extend them to be passed into my functions without worrying about misspelling property names or passing in the wrong argument. Any ideas on how to implement this, or where I could utilize an existing implementation?

I don't see any other way to enforce this. It's one of the side effects of the dynamic nature of JavaScript. It's essentially a free-for-all, and with that freedom comes responsibility :-)

If you're in need of type checking you could have a look at typescript (it's not JavaScript) or google's closure compiler (javascript with comments).
Closure compiler uses comments to figure out what type is expected when you compile it. Looks like a lot of trouble but can be helpful in big projects.
There are other benefits that come with closure compiler as you will be forced to produce comments that are used in an IDE like netbeans, it minifies your code, removes unused code and flattens namespaces. So code organized in namespaces like myApp.myModule.myObject.myFunction will be flattened to minimize object look up.
Cons are that you need to use externs when you use libraries that are not compiler compatible like jQuery.

The way that this kind of thing is typically dealt with in javascript is to use defaults. Most of the time you simply want to provide a guarentee that certain members exist to prevent things like reference errors, but I think that you could use the principal to get what you want.
By using something like jQuery's extend method, we can guarentee that a parameter implements a set of defined defaults.
var defaults = {
prop1: 'exists',
prop2: function() { return 'foo'; }
};
function someCall(args) {
var options = $.extend({}, defaults, args);
// Do work with options... It is now guarentee'd to have members prop1 and prop2, defined by the caller if they exist, using defaults if not.
}
If you really want to throw errors at run time if a specific member wasn't provided, you could perhaps define a function that throws an error, and include it in your defaults. Thus, if a member was provided by the caller, it would overwrite the default, but if it was missed, it could either take on some default functionality or throw an error as you wish.

Related

"use strict" and naming arguments in function calls

A colleague advised me to add "use strict"; to the top of my JS code to highlight any gaps in my definitions and potential reference errors, etc. I am very happy with it because it has identified several pieces of code which might have been a problem down the line.
However, another colleague advised me that when calling functions which take multiple arguments, it can be helpful to name the arguments as they are specified, especially if it's something like a bunch of booleans. To illustrate, here's a couple of function calls:
logData(data, target, preserveLog=true, changeClass=false, wrapLine=false);
...is a whole lot clearer than:
logData(data, target, true, false, false);
But "use strict"; hates this. everywhere I've done this, I get a reference error in the console. It still runs fine, as would be expected, but the console is now cluttered with all these apparently non-defined references.
Does anyone know if there's a way around this so that I can keep my coding conventions which my colleagues appreciate, or am I going to have to either stop using "use strict"; or go through all my code and remove the names of arguments?
Thanks.
However, another colleague advised me that when calling functions which take multiple arguments, it can be helpful to name the arguments as they are specified, especially if it's something like a bunch of booleans.
This is terrible advice!
Javascript doesn't actually support passing arguments by name this way. Each of the arguments you pass "by name" is actually being treated as an assignment to a global variable with that name, and "use strict" is correctly identifying this as an error.
If you want to be more clear about what values you're passing, assign the values to real local variables and pass those, e.g.
var preserveLog = true;
var changeClass = false;
var wrapLine = false;
logData(data, target, preserveLog, changeClass, wrapLine);
If you really wanted to keep using your original pattern, you could even assign to those variables in the function call, so long as you declare them as local variables first:
var preserveLog, changeClass, wrapLine;
logData(data, target, preserveLog=true, changeClass=false, wrapLine=false);
(With a hat-tip to dav_i for this answer, which I based my recommendation off of.)
Duskwuff has already provided an excellent answer and I won't add anything to that, other than to say I fully agree with it, but he didn't mention any conventions that arose due to ES6.
In ES6, you still don't have named parameters, but you have the next best thing, which is Object destructuring assignment.
This allows us to pass what appears to be named parameters, but are really just destructured object properties of an object that is never directly used.
In the context of the example you provided, it would look something like this:
logData({data, target, preserveLog:true, changeClass:false, wrapLine:false});
Where the function is defined as:
function logData({data, target, preserveLog, changeClass, wrapLine}) { ... }
I've seen a lot of libraries that prefer this calling convention where ES6 is available, and it's very convenient too because the order of the parameters is also no longer important.

How exactly stream.Transform works in Node?

Below is a code snippet I found online on a blog which entails a simple example in using the stream Transform class to alter data streams and output the altered result. There are some things about this that I don't really understand.
var stream = require('stream');
var util = require('util');
// node v0.10+ use native Transform, else polyfill
var Transform = stream.Transform ||
require('readable-stream').Transform;
Why does the program need to check if the this var points to an instance of the Upper constructor? The Upper constructor is being used to construct the upper object below, so what is the reason to check for this? Also, I tried logging options, but it returns null/undefined, so what's the point of that parameter?
function Upper(options) {
// allow use without new
if (!(this instanceof Upper)) {
return new Upper(options);
}
I assume that this Transform.call method is being made to explicitly set the this variable? But why does the program do that, seeing as how Transform is never being called anyway.
// init Transform
Transform.call(this, options);
}
After googling the util package, I know that it is being used here to allow Upper to inherit Transform's prototypal methods. Is that right?
util.inherits(Upper, Transform);
The function below is what really confuses me. I understand that the program is setting a method on Upper's prototype which is used to transform data being input into it. But, I don't see where this function is being called at all!
Upper.prototype._transform = function (chunk, enc, cb) {
var upperChunk = chunk.toString().toUpperCase();
this.push(upperChunk);
cb();
};
// try it out - from the original code
var upper = new Upper();
upper.pipe(process.stdout); // output to stdout
After running the code through a debugger, I can see that upper.write calls the aforementioned Upper.prototype._transform method, but why does this happen? upper is an instance of the Upper constructor, and write is a method that doesn't seem to have any relation to the _transform method being applied to the prototype of Upper.
upper.write('hello world\n'); // input line 1
upper.write('another line'); // input line 2
upper.end(); // finish
First, if you haven't already, take a look at the Transform stream implementer's documentation here.
Q: Why does the program need to check if the this var points to an instance of the Upper constructor? The Upper constructor is being used to construct the upper object below, so what is the reason to check for this?
A: It needs to check because anyone can call Upper() without new. So if it's detected that a user called the constructor without new, out of convenience (and to make things work correctly), new is implicitly called on the user's behalf.
Q: Also, I tried logging options, but it returns null/undefined, so what's the point of that parameter?
A: options is just a constructor/function parameter. If you don't pass anything to the constructor, then obviously it will be undefined (or whatever value you pass to it). You can have as many parameters as you want/need, just like any ordinary function. In the case of Upper() however, configuration isn't really needed due to the simplicity of the transform (just converting all input to uppercase).
Q: I assume that this Transform.call method is being made to explicitly set the this variable? But why does the program do that, seeing as how Transform is never being called anyway.
A: No, the Transform.call() allows the inherited "class" to perform its own initialization, such as setting up internal state variables. You can think of it as calling the super() in ES6 classes.
Q: After googling the util package, I know that it is being used here to allow Upper to inherit Transform's prototypal methods. Is that right?
A: Yes, that is correct. However, these days you can also use ES6 classes to do real inheritance. The node.js stream implementers documentation shows examples of both inheritance methods.
Q: The function below is what really confuses me. I understand that the program is setting a method on Upper's prototype which is used to transform data being input into it. But, I don't see where this function is being called at all!
A: This function is called internally by node when it has data for you to process. Think of the method as being part of an interface (or a "pure virtual function" if you are familiar with C++) that you are required to implement in your custom Transform.
Q: After running the code through a debugger, I can see that upper.write calls the aforementioned Upper.prototype._transform method, but why does this happen? upper is an instance of the Upper constructor, and write is a method that doesn't seem to have any relation to the _transform method being applied to the prototype of Upper.
A: As noted in the Transform documentation, Transform streams are merely simplified Duplex streams (meaning they accept input and produce output). When you call .write() you are writing to the Writable (input) side of the Transform stream. This is what triggers the call to ._transform() with the data you just passed to .write(). When you call .push() you are writing to the Readable (output) side of the Transform stream. That data is what seen when you either call .read() on the Transform stream or you attach a 'data' event handler.

How do I make JSHint complain about missing function parameters?

If I have a function:
export function createWeeklyStats(activities, offset, length) {
...
}
And I call the function like:
createWeeklyStats(myListOfActivities, 0)
JSHint does not complain that I'm missing the length parameter. I could not find a matching enforcing option here:
JSHint Options Reference
Does one exist?
I'm updating an existing method to include a new required parameter, and while I'm a self-proclaimed adult, I'll throw a fit right here if my best way out is a full-text search.
The commenters are correct that there is no way to ask js[hl]int to find this.
Here are some options:
Explicitly check arg count
Check argument count:
function createWeeklyStats(activities, offset, length) {
assert(arguments.length === 3);
Granted, that will raise the error at run-time, rather than compile-time.
Perhaps you want to write a little higher-order function which helps you out here:
function check_arg_count(f) {
return function() {
assert(arguments.length === f.length);
return f.apply(this, arguments);
};
}
Now instead of calling createWeeklyStats, you call check_arg_count(createWeeklyStats).
I don't see anything particularly wrong with this approach. It will be a little tricky dealing with optional arguments. At some point, you might want to throw in the towel and make the move to a more strongly typed language or TypeScript.
Use a refactoring tool
In this case you are refactoring, so how about using a refactoring tool? Many editors/IDE have such features. Check out the documentation.
There are other tools to help with refactoring. For instance, take a look at grasp. Actually, the grasp tutorial describes a similar case involving refactoring a function's argument list:
$ grasp -r -e 'createWeeklyStats($a, $o)' -R 'createWeeklyStats($a, $o, 0)' })' .
This will add the third argument to all calls. Changing the new third parameter is something you will obviously have to take care of yourself. grasp provides other features to narrow the scope of the change.
Customize the linter
You can write custom rules for eslint (but apparently not jshint; see this question). This could get you started: https://gist.github.com/jareware/7179093. Also http://eslint.org/docs/developer-guide/working-with-rules.html.

Testing scenarios with exponentially growing outcomes

One of the things that really draws me to TDD is the clear development of your spec alongside implementation.
I am seeking to implement a constructor that accepts a configuration object
function MyConstructor(conf) {}
conf is currently spec'd to have two keys: a and b, where a is a RegExp and b is a Function, and as part of my TDD spec elucidation ambitions, I am writing tests that spec out this object as such:
I would like MyConstructor to throw an Error if either a is not a RegExp or b is not a Function.
MyConstructor throws an Error if either a or b is missing from the configuration.
Now, I know that I could encapsulate this behavior in some other constructor, say a Configuration constructor that creates "configuration" objects. But the way I am seeing this now, regardless of where this behavior ends up, this behavior has to be encapsulated somewhere for this spec to be elaborated via TDD.
The problem is: I seems to me that as the number of keys on the conf object grows, so does the number of tests—exponentially! This is especially due to the second bullet above.
For example, say I have 4 keys: a, b, c and d, and I need to make sure that if any are missing an Error is thrown. It seems that this requires that I write a ton of identical, banal tests that cover all the possibilities (combinations!) for missing keys. That doesn't sound right! Yet, I can't think of a good way explicitly or inductively test that all scenarios are covered. Any thoughts?
Objects without a class definition or interface are hard to test. If your objects are ducks you'll need to use ducktyping to check.
You can also wonder about how useful it is to completely test certain functions. You can test the boundaries but you can never test all values;
If your function looks like this:
function sum(a, b) {
if (a === 42) {
throw new Error("All glory to the hypnotoad");
}
return a + b;
}
how are you expected to find this bug?
I would suggest you use Duck Typing to enforce the types. Essentially, what you'll do is use the objects passed in by your keys as you'd expect them to, and let the JS runtime complain if, say, a doesn't behave like a RegEx or you can't call b like a function.

Javascript - Passing arguments to function

I've always passed arguments to a function like so:
setValue('foo','#bar')
function setValue(val,ele){
$(ele).val(val);
};
Forgive the silly example. But recently I have been working on a project that has some functions that take a lot of arguments. So I started passing the arguments through as an object (not sure if that's the correct way to put that), like so:
setValue({
val:'foo',
ele:'#bar'
});
And then in the function:
function setValue(options){
var value = options.val;
var element = options.ele;
$(element).val(value);
};
My question is, is there a better way to do that? Is it common practice (or okay) to call these 'options'? And do you typically need to 'unpack' (for lack of a better term) the options and set local vars inside the function? I have been doing it this way in case one of them was not defined.
I'm really looking to not create bad habits and write a bunch of code that is ugly. Any help is appreciated and + by me. Thanks.
I do the exact same thing, except I don't declare a new variable for each option inside the function.
I think options is a good name for it although I shorten it to opts.
I always have a "default" object within the function that specify default values for each available option, even if its simply null. I use jQuery, so I can just use $.extend to merge the defaults and user-specified options like this: var opts = $.extend({}, defaults, opts);
I believe this is a great pattern. I've heard an options object like this referred to as a "builder object" in other languages (at least in the context of object creation). Here are some of the advantages:
Users of your function don't have to worry about what order the parameters are in. This is especially helpful in cases like yours where the method takes a lot of arguments. It's easy to get those mixed up, and JavaScript will not complain!
It's easy to make certain parameters optional (this comes in handy when writing a plugin or utility).
There are some pitfalls though. Specifically, the user of your function could not specify some of the options and your code would choke (note that this could also happen with a normal JS function: the user still doesn't have to supply the correct arguments). A good way for handling this is to provide default values for parameters that are not required:
var value = options.val || 0;
var element = options.ele || {};
$(element).val(value);
You could also return from the function immediately or throw an exception if the correct arguments aren't supplied.
A good resource for learning how to handle builder objects is to check out the source of things like jQueryUI.
I realize this question is a year old, but I think the cleanest way to pass an arbitrary number of arguments to a JavaScript function is using an array and the built in apply method:
fun.apply(object, [argsArray])
Where fun is the function, object is your scope/context in which you want the function to be executed and the argsArray is an array of the arguments (which can hold any number of arguments to be passed.
The current pitfall right now is that the arguments must be an array (literal or object) and not an array-like object such as {'arg' : 6, 'arg2' : "stuff"}. ECMAScript 5 will let you pass array-like objects, but it only seems to work in FireFox at the moment and not IE9 or Chrome.
If you look at the jQuery implementation, it uses an options class to handle most of the arbitrary-number-of-parameters functions, so I think you are in good company.
The other way is to test for arguments.length, but that only works if your arguments are always in the same order of optionality.
It's worth remembering that all functions have a bonus parameter called arguments that is an object very much like a JS array (it has length but none of the array functions) that contains all the parameters passed in.
Useful if you want to pass in a range of parameters (e.g.
function Sum() {
var i, sum = 0;
for (i=0; i < arguments.length; i++){
sum+=arguments[i];
}
return sum;
};
If this isn't the case and you just have a lot of parameters, use the params object as you've described.
Nothing wrong with that practice.
"Options" seems like as good a name as any.
You don't need to "unpack" them, but if you'll be accessing the same item several times, it will be a little more efficient to reference them in local variables because local variable access is generally quicker than property lookups.

Categories