I am reading a book where it says one way to handle impure functions is to inject them into the function instead of calling it like the example below.
normal function call:
const getRandomFileName = (fileExtension = "") => {
...
for (let i = 0; i < NAME_LENGTH; i++) {
namePart[i] = getRandomLetter();
}
...
};
inject and then function call:
const getRandomFileName2 = (fileExtension = "", randomLetterFunc = getRandomLetter) => {
const NAME_LENGTH = 12;
let namePart = new Array(NAME_LENGTH);
for (let i = 0; i < NAME_LENGTH; i++) {
namePart[i] = randomLetterFunc();
}
return namePart.join("") + fileExtension;
};
The author says such injections could be helpful when we are trying to test the function, as we can pass a function we know the result of, to the original function to get a more predictable solution.
Is there any difference between the above two functions in terms of being pure as I understand the second function is still impure even after getting injected?
An impure function is just a function that contains one or more side effects that are not disenable from the given inputs.
That is if it mutates data outside of its scope and does not predictably produce the same output for the same input.
In the first example NAME_LENGTH is defined outside the scope of the function - so if that value changes the behaviour of getRandomFileName also changes - even if we supply the same fileExtension each time. Likewise, getRandomLetter is defined outside the scope - and almost certainly produces random output - so would be inherently impure.
In second example everything is referenced in the scope of the function or is passed to it or defined in it. This means that it could be pure - but isn't necessarily. Again this is because some functions are inherently impure - so it would depend on how randomLetterFunc is defined.
If we called it with
getRandomFileName2('test', () => 'a');
...then it would be pure - because every time we called it we would get the same result.
On the other hand if we called it with
getRandomFileName2(
'test',
() => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.charAt(Math.floor(25 * Math.random()))
);
It would be impure, because calling it each time would give a different result.
There's more than one thing at stake here. At one level, as Fraser's answer explains, assuming that getRandomLetter is impure (by being nondeterministic), then getRandomFileName also is.
At least, by making getRandomFileName2 a higher-order function, you at least give it the opportunity to be a pure function. Assuming that getRandomFileName2 performs no other impure action, if you pass it a pure function, it will, itself, transitively, be pure.
If you pass it an impure function, it will also, transitively, be impure.
Giving a function an opportunity to be pure can be useful for testing, but doesn't imply that the design is functional. You can also use dependency injection and Test Doubles to make objects deterministic, but that doesn't make them functional.
In most languages, including JavaScript, you can't get any guarantees from functions as first-class values. A function of a particular 'shape' (type) can be pure or impure, and you can check this neither at compile time nor at run time.
In Haskell, on the other hand, you can explicitly declare whether a function is pure or impure. In order to even have the option of calling an impure action, a function must itself be declared impure.
Thus, the opportunity to be impure must be declared at compile time. Even if you pass a pure 'implementation' of an impure type, the receiving, higher-order function still looks impure.
While something like described in the OP would be technically possible in Haskell, it would make everything impure, so it wouldn't be the way you go about it.
What you do instead depends on circumstances and requirements. In the OP, it looks as though you need exactly 12 random values. Instead of passing an impure action as an argument, you might instead generate 12 random values in the 'impure shell' of the program, and pass those values to a function that can then remain pure.
There's more at stake than just testing. While testability is nice, the design suggested in the OP will most certainly be impure 'in production' (i.e. when composed with a proper random value generator).
Impure actions are harder to understand, and their interactions can be surprising. Pure functions, on the other hand, are referentially transparent, and referential transparency fits in your head.
It'd be a good idea to have as a goal pure functions whenever possible. The proposed getRandomFileName2 is unlikely to be pure when composed with a 'real' random value generator, so a more functional design is warranted.
Anything that contains random (or Date or stuff like that). Will be considered impure and hard to test because what it returns doesn't strictly depends on its inputs (always different). However, if the random part of the function is injected, the function can be made "pure" in the test suite by replacing whatever injected randomness with something predictable.
function getRandomFileName(fileExtension = "", randomLetterFunc = getRandomLetter) {}
can be tested by calling it with a predictable "getLetter" function instead of a random one:
getRandomFileName("", predictableLetterFunc)
Related
What I need to do
I need to detect whether two objects are the same. By same I mean deep-equal: different objects that look and behave the same are the same to me. For instance {} is the same as {}, even though {} != {}.
I need to do this on Node.js.
Problem
This has been easy with most types I handle (undefined, null, numbers, NaN, strings, objects, arrays), but it's proving really hard with functions.
For function I would consider two functions to be the same if their name and code is identical. In case the functions are closures, then the variables they capture need to be the same instance.
I don't know how to implement that.
Attempted solutions
These are all the approaches I could think of to compare functions, but they all have issues:
Comparing the function with == or === doesn't work, of course. Example ()=>0 != ()=>0, but they should be the same.
Comparing the function name doesn't work, of course. Example: ()=>0 === ()=>1 when they shouldn't be the same.
Comparing the function's code (as reported by Function.prototype.toString) doesn't work:
const fnFactory=(n)=>{ return ()=>n; };
const fn1=fnFactory(0);
const fn2=fnFactory(1);
fn1.toString() === fn2.toString()
But they shouldn't be the same.
Compare the functions' code. If it's the same, parse it and detect whether the function has any captured variables, if it doesn't, the functions are the same.
This solution however would be unbearably slow. Besides it still doesn't work for different functions that capture the same instances of variables.
What I need this for (example)
I need this in order to implement a factory function like this (this is just a minimal example, of course):
// Precondition:
// "factoryFn" is called only once for every value of "fn"
// the result is then reused for every future invocation.
const storage=new MagicStorage();
function createOrReuse(fn, ...opts)
{
if(storage.has(fn, ...opts)){
return storage.get(fn, ...opts);
}
else{
const data=factoryFn(...opts);
storage.set(data, fn, ...opts);
return data;
}
}
Then I want to use it in several places around my code. For instance:
function f1(n) {
// ...
const buffer=createOrReuse((n)=>new Buffer.alloc(n*1024*1024), n);
//...
}
function f2(){
//...
emitter.on('ev', async()=>{
const buffer=await createOrReuse(()=>fs.readFile('file.txt'));
// ...
});
//...
}
Of course there are other ways to achieve the same result: For instance I could store the allocated values in variables with a lifetime long enough.
However similar solutions are much less ergonomic. I wish to have that small createOrReuse function. In other languages (like C++) such a createOrReuse could be implemented. Can I not implement it in Javascript?
Question
Is it possible to implement the function-comparison logic I need in pure JavaScript? I can use any ES version.
Otherwise is it possible to implement it as a native module for Node.js?
If yes, Is there any Node.js native module that can be used to achieve what I need?
Otherwise, where can I start to develop one?
An article I was reading gives this as an example of an impure function (in JavaScript):
const tipPercentage = 0.15;
const calculateTip = cost => cost * tipPercentage;
That struck me as a bit of an odd example, since tipPercentage is a constant with an immutable value. Common examples of pure functions allow dependence on immutable constants when those constants are functions.
const mul = (x, y) => x * y
const calculateTip = (cost, tipPercentage) => mul(cost, tipPercentage);
In the above example, correct me if I'm wrong, calculateTip would usually be categorised as a pure function.
So, my question is: In functional programming, is a function still considered pure if it relies on an externally defined constant with an immutable value, when that value is not a function?
Yes, it is a pure function. Pure functions are referentially transparent, i.e. one can replace the function call with its result without changing the behaviour of the program.
In your example, it is always valid to replace e.g. calculateTip (100) anywhere in your program with its result of 15 without any change in behaviour, hence the function is pure.
Yes, theoretically, a function that abides by these two rules:
not causing side effects
not depending on "any mutable state"
can be considered pure, and as #TheInnerLight has put it well, provides referential transparency among other benefits. That makes the function in your example pure.
However, as the question is about & tagged with javascript, it is important to note that a function that depends on a const defined in the outer scope cannot always be considered pure:
const state = {}
function readState (key) {
return state[key]
}
// A hypothetical setState() can mutate `state` and
// therefore change the outcome of `readState` calls.
That is obviously because state value is not immutable (only the assignment is).
The rule of thumb is to prefer local over global when it comes to scopes. That provides better isolation, debuggability, and less cognitive load for the next reader.
I'm wondering what the best practice is regarding using declared constants in JavaScript. Is it better to pass the constant as an argument to the function or is it better to use the constant without passing?
My instinct is to not pass the constant as an argument because that produces an unnecessary local copy of the variable. However, it might be more clear where the constant is coming from if it is passed.
const myConstant = 1;
myFunc();
myOtherFunc(myConstant);
/* use constant without passing */
function myFunc() {
console.log(`${myConstant} is a constant`);
}
/* pass constant as argument */
function myOtherFunc(localCopy) {
console.log(`${localCopy} is a constant`);
}
There are tradeoffs going in both directions, though most of them are in the area of unit testing and re-usability.
The more you hard code things, the less flexibility you have in testing.
Let me give what a contrived example:
const FIRST_NAME_MAX_LEN = 20;
And, in our validation code, we look at that constant and compare it to the length of the input field...
function validateFirstName() {
return document.getElementsByName("first-name")[0].length <= FIRST_NAME_MAX_LEN;
}
Ok, this works, but we have no way to test that validateFirstName() works without invoking the entire DOM. it is harder to test.
On the other hand, if we create a function like:
function validateStringLength(s, maxLength) {
return s.length <= maxLength;
}
then we've created a function that takes passed parameters, is re-usable in other places and very easily tested in any testing framework. DOM not required.
By relying upon the constant, you have created a dependency on that value and where it live. Research JavaScript Dependency Injection for much more on this topic.
While I was investigating functions, I realised that I can create embedded functions. Firstly, I thought it may be useful for structuring code. But now I suppose it isn't good style of coding. Am I right? Here is an example.
function show () {
return function a() {
alert('a');
return function b() {
alert('b');
}
}
}
And I can call alert('b') using this string: show()();
In what situations is better to use this method and in what not?
Yes, this has many uses.
Currying
Firstly, you may want to use currying, where you encapsulate a function with a single argument with a function with many arguments. For example,
function getHandler(num){
return function(){
alert(num);
}
}
myElement.onclick=getHandler(1)
myOtherElement.onclick=getHandler(25)
anotherElement.onclick=getHandler(42)
onclick() cannot be given arbitrary arguments as it is called by the system. Instead of writing 3 different handlers that alert different numbers, this reduces the bloat by creating a function that can generate arbitrary handlers of the "alert a number" type. Of course, this is a rather simplistic example, but if one had to do something considerably more complicated than alert(), the benefits of currying are evident.
Efficiency
Another situation is when you have a complicated function that has one computationally-heavy portion, which is followed by a computationally-light portion. The two portions take different parameters, and usually the parameters for the first portion will be the same. Some variation of memoization can be used to solve this, but function-as-return value works too.
For example, let's say you have a function of the following form:
function doSomething(a,b,c,x,y){
//Do some complicated calculations using a,b,c, the results go to variables e,f,g
//Do some simple calculations using e,f,g,x,y, return result
}
If I want to run doSomething(1,2,3,18,34)+doSomething(1,2,3,55,35)+doSomething(1,2,3,19,12), it would take 3 times the execution time as the long part is execute every time.
However, we can write it as:
function doSomethingCreator(a,b,c){
//Do some complicated calculations using a,b,c, the results go to variables e,f,g
return function(x,y){
//Do some simple calculations using e,f,g,x,y, return result
}
}
Now, all I need to do is call doSomethingCreator() for my set of parameters, and use the created function (which is fast) to get the final results. The code becomes:
var doSomething123=doSomethingCreator(1,2,3);
console.log(doSomething123(18,34)+doSomething123(55,35)+doSomething123(19,12))
One example of this is solving differential equations. Differential equations do not have a single solution if some "boundary conditions" are given. However, (especially for homogenous equations), after one point it is easy to vary the boundary conditions and get solutions. And usually one needs to solve the same equation for different boundary conditions multiple times. So, if you want to write a library method, you would have it take the homogenous equation as the input, and it would return a function, which in turn can be given the boundary conditions as an input to get the final solution.
"Static" variables via closures
Sometimes, you want to be able to easily create a set of variables and carry them around.
For example, if you want to create a counter function:
function generateCounter(){
var c=0;
return function(){
c++;
return c;
}
}
We can use this to make many independent counters, for example:
myCtr1=generateCounter();
myCtr2=generateCounter();
myCtr1(); //Returns 1
myCtr1(); //Returns 2
myCtr2(); //Returns 1
myCtr1(); //Returns 3
myCtr2(); //Returns 2
Each counter is independent. Of course, in this case, it would be easier to jut use myCtr1=0;myCtr2=0 and then the ++ operator, but what if you want to record the times when they were incremented? Extending the ++ case would involve a lot of code duplication, however, here we can tweak it pretty easily:
function generateCounter(){
var c=[]; // The length of c is the value of the counter
return function(){
c.push((new Date()).getTime());
return c;
}
}
When you should not use it
Whenever there is no obvious gain in doing so.
Aside from when you want to use it for closure-bound variables, there usually isn't much point in doing it with 0 arguments for the outer function as the inner function becomes the same function. See if it really improves the program, and then use it.
This is one of the most common styles of coding in Javascript and some other languages which treat their functions as first class citizens. One of the most uses of these nested declarations is in creating closures and currying.
I often find that I write IF statements which immediately reference the value of the conditional statement. For example, let's say I need to check to see if a string matches a pattern:
if (mystring.match(/mypattern/) {
var mymatch = mystring.match(/mypattern/)[1];
...
};
I suspect that what I'm looking for doesn't exist, but I've wondered whether you can reference the conditional statement's value within the if block, the way you can reference "arguments" within a function. In many cases, of course, I can rewrite it like this:
var mymatch = mystring.match(/mypattern/)[1];
if (mymatch) { ... };
But that's often not possible if there's a series of methods called. For example:
var mymatch = $('.myclass')[0].text().match(/mypattern/)[1];
... that would throw an exception if there were no item [0] on which to call .text(). Is there some convenient shorthand I'm missing out on? Or a better way to organize things? Just curious, really — I'll go on living if the answer is no.
In cases where relevant you can use the fact that the assignment operator returns a value in JavaScript, so for instance you can write things like:
if (assignedTest = testedValue) {
//value of assignedTest is now available
//and conditional will only be executed if true
This could be used if the RHS was compatible or properly set-up but it's also a huge readability concern since it's very easy to confuse the assignment = with comparison ==/===.
If you were particularly motivated to pursue this you could extract this type of functionality into a function that would behave in a reliable way: such as assigning the result of a closure to a named variable, and you could further tune the behavior to do other things (such as optionally evaluating to a different value within the test). Ultimately it would primarily be making a simple structure more complex though.