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.
Related
Minimal example: Say I have the higher-order function
const my_fn = (a) => (b) => a + b
that, when called like so:
my_fn(42)
returns the function (b) => 42 + b.
Would it be correct to refer to my_fn as a "template function"?
I know that, in languages such as C++, the word "template" has a very specific technical meaning.
But in JavaScript, there is (AFAIK) no built-in template in syntax in the way that there is in C++.
I don't want to abuse terminology.
Is it correct to refer to higher-order functions in JS as template functions, and vice-versa?
(related, optional question: is there a difference between skillfully using higher-order functions in JS and doing "generic programming" in this language?)
I wouldn't call this a “template” function, though I might call this function a “function factory.” To me, the word “template” in languages like C++ implies the specific goal of applying one function to a range of different data types.
A function like the example you gave doesn’t really accomplish anything new in terms of “generic programming” because it's not designed to produce functions that operate on different types of values. Javascript is not strict about types, so you can pass a value of any type to your function and the language will do its best to work with it. You don't have to do anything additional to make a function apply to different types of objects; every function accepts every kind of object unless the programmer adds explicit typechecking logic.
This may border on philosophical, but I thought it would be the right place to ask.
Suppose I have a function that creates a list of IDs. These identifiers are only used internally to the application, so it is acceptable to use ES2015 Symbol() here.
My problem is that, technically, when you ask for a Symbol, I'd imagine the JS runtime creates a unique identifier (random number? memory address? unsure) which, to prevent collisions, would require accessing global state. The reason I'm unsure is because of that word, "technically". I'm not sure (again, from a philosophical standpoint) if this ought to be enough to break the mathematical abstraction that the API presents.
tl;dr: here's an example--
function sentinelToSymbol(x) {
if (x === -1) return Symbol();
return x;
}
Is this function pure?
Not really, no, but it might not actually matter.
On the surface, (foo) => Symbol(foo) appears pure. While the runtime may do some operations with side effects, you will never see them, even if you call Symbol() at the same time with the same parameters. However, calling Symbol with the same arguments will never return the same value, which is one of the main criteria (#2, below).
From the MDN page:
Note that Symbol("foo") does not coerce the string "foo" into a symbol. It creates a new symbol each time:
Symbol("foo") === Symbol("foo"); // false
Looking solely at side effects, (foo) => Symbol(foo) is pure (above the runtime).
However, a pure function must meet more criteria. From Wikipedia:
Purely functional functions (or expressions) have no side effects (memory or I/O). This means that pure functions have several useful properties, many of which can be used to optimize the code:
If the result of a pure expression is not used, it can be removed without affecting other expressions.
If a pure function is called with arguments that cause no side-effects, the result is constant with respect to that argument list (sometimes called referential transparency), i.e. if the pure function is again called with the same arguments, the same result will be returned (this can enable caching optimizations such as memoization).
If there is no data dependency between two pure expressions, then their order can be reversed, or they can be performed in parallel and they cannot interfere with one another (in other terms, the evaluation of any pure expression is thread-safe).
If the entire language does not allow side-effects, then any evaluation strategy can be used; this gives the compiler freedom to reorder or combine the evaluation of expressions in a program (for example, using deforestation).
You could argue the preface to that list rules out everything in JavaScript, since any operation could result in memory being allocated, internal structures updated, etc. In the strictest possible interpretation, JS is never pure. That's not very interesting or useful, so...
This function meets criteria #1. Disregarding the result, (foo) => Symbol(foo) and (foo) => () are identical to any outside observer.
Criteria #2 gives us more trouble. Given bar = (foo) => Symbol(foo), bar('xyz') !== bar('xyz'), so Symbol does not meet that requirement at all. You are guaranteed to get a unique instance back every time you call Symbol.
Moving on, criteria #3 causes no problems. You can call Symbol from different threads without them conflicting (parallel) and it doesn't matter what order they are called in.
Finally, criteria #4 is more of a note than direct requirement, and is easily met (the JS runtimes shuffle everything around as they go).
Therefore:
strictly speaking, nothing in JS can be pure.
Symbol() is definitely not pure, thus the example is not either.
If all you care about is side effects rather than memoization, the example does meet those criteria.
Yes, this function is impure: sentinelToSymbol(-1) !== sentinelToSymbol(-1). We would expect equality here for a pure function.
However, if we use the concept of referential transparency in a language with object identities, we might want to loosen our definition a bit. If you consider function x() { return []; }, is it pure? Obviously x() !== x(), but still the function always returns an empty array regardless of the input, like a constant function. So what we do have to define here is the equality of values in our language. The === operator might not be the best fit here (just consider NaN). Are arrays equal to each other if the contain the same elements? Probably yes, unless they are mutated somewhere.
So you will have to answer the same question for your symbols now. Symbols are immutable, which makes that part easy. Now we could consider them equal by their [[Description]] value (or .toString()), so sentinelToSymbol would be pure by that definition.
But most languages do have functions that allow to break referential transparency - for example see How to print memory address of a list in Haskell. In JavaScript, this would be using === on otherwise equal objects. And it would be using symbols as properties, as that inspects their identity. So if you do not use such operations (or at least without being observable to the outside) in your programs, you can claim purity for your functions and use it for reasoing about your program.
What seems to make many Java peeps anxious about JS is its "cool dad" nature; it doesn't care if you smoke pot or hang out with your friends until 2am. Without that structure, it's impossible to check for type safety at "compile time"... or is it?
Of course, javascript has types, but it's not strongly typed. That being said, a human reading the following excerpt will notice that this is going to throw a runtime exception:
function f(anArray) {
"use strict";
anArray.push("hi");
}
f(5); //runtime exception for sure
We can see this as programmers because, even though types aren't explicitly declared (e.g. int c;), we can gather various other characteristics to deduce its type (it's a number without quotes). It seems like there's an algorithm (such as a decision tree) that could easily infer the type of a given object.
The essence is that in a dynamically typed language, types exist, but their use and conversions are implicit. My question, then, is:
Is it plausible that linters could use implicit conventions to determine what the intended type of a method is, and warn about a potential runtime error at "lint time"?
Thank you in advance.
Code inspectors like linters or type checkers can only go "that far" in analysing code to spot type incompatibilities.
Consider for instance this code:
function f(a) {
return a%2 ? [a] : false;
}
x = [];
for (var i=1; i < 10; i+=2) {
x = f(i).concat(x);
}
document.write(x);
This will not be a problem; but it would have been if i had started at 2 instead of 1. In general the value passed to f could be the result of a complex algorithm, and a code inspector would have to actually run the code to know the result. This of course is not the idea of such a tool, and so in practice it is only possible to find trivial cases of type incompatibilities.
I would advise that you take a look at Tern, you can install it into your text editor (or just run it as a executable), and it will attempt to determine the type of a variable in a certain scope, and offers tools such as code completion, method suggestions (based off of determined type), function argument hints, etc. It's not perfect, but works very well based on JavaScript's limitations.
The MDN gives the following working example of Symbol.species:
class MyArray extends Array {
// Overwrite species to the parent Array constructor
static get [Symbol.species]() { return Array; }
}
var a = new MyArray(1,2,3);
var mapped = a.map(x => x * x);
console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // true
The ECMAScript 2015 specifications says:
A function valued property that is the constructor function that is used to create derived objects.
The way I understand it it would be mainly used to Duck-Type in some way custom objects in order to trick the instanceof operator.
It seems very useful but I have not managed to use it on plain objects (FF 44.0a2):
let obj = {
get [Symbol.species]() {
return Array
}
}
console.log(obj instanceof Array) //false =(
console.log(obj instanceof Object) //true
Is there any way to use Symbol.species on plain objects in order to trick the instanceof operator?
The way I understand it it would be mainly used to Duck-Type in some way custom objects in order to trick the instanceof operator.
Nope, that's what Symbol.hasInstance is good for (though it makes tricky constructors, e.g. for mixins, not tricky instances).
The point of Symbol.species is to let built-in methods determine the proper type for derived objects. Whenever a function is supposed to return a new instance of the same kind, it usually instantiates a new this.constructor, which might be a subclass of the class that defined the method. But you might not always want this when subclassing, and that's where Symbol.species comes in.
The example given by MDN is quite good, you just must not miss the distinction between a and mapped:
var a = new MyArray(1,2,3);
var mapped = a.map(x => x * x);
Object.getPrototypeOf(a) == MyArray.prototype; // true
Object.getPrototypeOf(mapped) == Array.prototype; // true
(As you know, instanceof is was just sugar for the reverse of isPrototypeOf)
So what happens here is that the Array map method is called on an instance of MyArray, and creates a derived object that is now an instance of Array - because a.constructor[Symbol.species] said so. Without it, map would have created another MyArray.
This trick would work with plain objects just as well:
var b = {
length: 0,
map: Array.prototype.map,
constructor: { // yes, usually a function
[Symbol.species]: MyArray
}
};
var mapped = b.map(x => x*x);
console.log(mapped instanceof MyArray); // true
I can't say whether it's any useful in this example, though :-)
Good question. I admit that I'm not 100% sure, but I've gotten the impression that the answer is no.
I used two methods to determine this answer:
Finding an environment that clearly supports all of the features necessary to test this, and running the code in that environment directly
Referencing the spec
The first point wasn't easy to test, and I wasn't entirely sure that I successfully did it. You used Firefox 44, but I decided to test another environment due to the fact that Kangax's support table says it only supports the existence of Symbol.species, and none of the Array-like features. To see this, you can expand the Symbol.species section in the link above.
In this case, even Kangax is a bit confusing. I would expect there to be non-Array specific tests for Symbol.species aside from the existence test, but maybe I'm just not knowledge enough to understand that those tests cover all of the functionality of Symbols. I'm not sure!
While browsing the table, I saw that Edge supports all of the Symbol.species features. I loaded up my Windows VM, hopped on over to Edge 20, and pasted your code.
In Edge 20, the code had the same result as your test in Firefox 44.
So this began to give me confidence that the feature doesn't work in the way that you want it to. Just to make sure that Edge had its JavaScript in order, I decided to run the code from the MDN article you linked, and...I got a syntax error! It appears Edge is still updating its Class implementation due to late-in-the-game changes to the Class spec, so it's not enabled.
Their current implementation is, however, available through an experimental flag. So I flipped that on and was able to reproduce the result that MDN got.
And that was the extent of my JavaScript environment testing. I don't have 100% confidence in this test, but I would say that I'm fairly confidence in the result.
So onto the second method I used to determine my result: the specification.
I admit that I'm no expert at the ECMAScript specification. I do my best to understand it, but it is likely that I might misinterpret some of the information in there. The reason for this is because I'm not an ECMAScript master, so some of the technical jargon used is just way over my head.
Nevertheless, I can sometimes get the gist of what is being said. Here's a snippet that's about the Symbol ##species:
Methods that create derived collection objects should call ##species to determine the constructor to use to create the derived objects. Subclass constructor may over-ride ##species to change the default constructor assignment.
The phrase "derived objects" is used quite frequently in describing this symbol, but it's not defined anywhere. One might interpret it to be a synonym of sorts with instantiated. If that's a correct interpretation, then this can likely only be used with constructors or classes.
Either way, it sounds as if ##species is an active Symbol, rather than a passive one. By this I mean that it sounds like it's a function that's actually called during the creation of an Object, which is then what determines the instanceof value, rather than a function that's called at the time of instanceof being called.
But anyway, take that interpretation with a grain of salt. Once again, I'm not 100% certain of any of this. I considered posting this as a comment rather than an answer, but it ended up getting quite long.
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.