I am building a simple application using Ramda.
I have run into a functional composition problem that I am not really sure how to address without creating what seems to be a needlessly absurd function.
The scenario:
I have an object being passed as a parameter. There are two attributes on this object, and some other stuff that isn't relevant to the problem other than that I'd like to not change it's state :
{locCode :<string>, LocationList : [<Location>], someOtherParams : ... }
I have a single arg function which can convert a locCode to a location:
fetchLocByCode
My desired result here would be to take the locCode value, pass it to fetchLocByCode, append LocationList with the result, and return a new object with the new LocationList without touching anything else on the object.
Something analagous to:
(Param)=>{
Param.LocationList.push(fetchLocByCode(Param.locCode));
return Param;
}
What I've ended up writing to do this seems extremely ridiculous and leads me to believe I have done something horribly wrong:
const locListLens = R.lens(R.prop('LocationList'),R.assoc('LocationList'))
const appendLocList = (i)=>R.compose(R.over(locListLens),R.append,fetchLocByCode,R.prop('locCode'))(i)(i)
This solution 'works' but it seems as if I've missed some fundamental idea.
Would anyone care to present a more 'canonical' way to address this scenario?
Let's start with your initial version:
Param => {
Param.LocationList.push(fetchLocByCode(Param.locCode));
return Param;
}
I very much hope the mutation is not required. Let's remove it:
Param =>
R.assoc('LocationList',
R.append(fetchLocByCode(Param.locCode), Param.LocationList),
Param)
We could use a lens to avoid accessing the LocationList property twice:
Param =>
R.over(R.lensProp('LocationList'),
R.append(fetchLocByCode(Param.locCode)),
Param)
Could we get rid of Param entirely? Let's start by using R.converge:
R.converge(R.over(R.lensProp('LocationList')),
[Param => R.append(fetchLocByCode(Param.locCode)),
R.identity])
Let's use R.compose to remove Param from the first branching function:
R.converge(R.over(R.lensProp('LocationList')),
[R.compose(R.append, fetchLocByCode, R.prop('locCode')),
R.identity])
Any time you find yourself writing R.converge(f, [g, R.identity]) you've discovered a use for the S combinator!
S.S(R.flip(R.over(R.lensProp('LocationList'))),
R.compose(R.append, fetchLocByCode, R.prop('locCode')))
Although this is neat, I think the R.assoc version is fine. Future readers would not enjoy having to make sense of S.S(R.flip(R.over(R.lensProp. ;)
Related
I was reading this article about creating react/redux applications
and was a bit confused by the following section, specifically the part I've circled in red. What exactly is happening here? I'm not very familiar with the syntax being used, the double "=>" is not something I've seen before. If you are able to explain this block of code that would be much appreciated!
Thanks
Not sure how much you understand Redux yet but you create actions for each task you want to record in the store, these are processed using reducers.
The createAction function, as it's name suggests creates actions, so rather than having to re-write the same code over and over you can call it, passing the name of the action you want to create. In this example the action being created is called SET_USER_ID
The arrow function => is new syntax introduced with the latest javascript which is known as ES6. You can read about it here. Arrow functions allow you to define functions using shorter syntax and they also solve scoping issues.
The final line would be used within your react component to call the action. i.e.
<Button onClick={ () => dispatch(setUserId('abcd123')) } />
It took me a while to get my head around redux, if you haven't watched Dan Abramov's tutorials on it then I highly recommend them. He's the creator of redux. Also start building your own redux app, that's the best way to learn.
"the double "=>" is not something I've seen before."
This is called currying is the technique of translating the evaluation of a function that takes multiple arguments, in this particular example
type, (payload, meta). Here, the function accepts the first argument (type) and returns a function that accepts the second arguments (payload, meta) and so on.
example: const sum = x => y => x + y;
sum (2)(1); // returns 3
sum (2); // returns a function y => 2 + y
Currying is the process of taking a function with multiple arguments and turning it into a sequence of functions each with only a single argument - a fancy name of Partial Application
https://en.wikipedia.org/wiki/Partial_application
First you call createAction and pass a type(SET_USER_ID) then you call setUserId and pass a payload (id in this case). 'Meta' is optional argument.
It is hard to wrap your head around it at first.
You can also write it this way
const newOPfunction = (type) => {
const newFunc = (id) => {
return {type, id}
}
return newFunc;
}
but it doesn't look as pretty
Below is my code. I don't think there is any problem.
How can I fool codacy? If I can't use obj[key], then what the hell is this thing? There is no way I can avoid [].
handleClick = (e, titleProps) => {
const { index } = titleProps
const newVal = this.state.activeIndexObj[index]? false: true
let activeIndexObj = {...this.state.activeIndexObj}
activeIndexObj[index] = newVal
// Generic Object Injection Sink (security/detect-object-injection)
You just need to parse index into integer
activeIndexObj[parseInt(index)] = newVal
there could be chances hacker may inject function or prototype chaining so that's why this security error comes.
the question linked on the comment by #luca (Why is it bad pratice calling an array index with a variable?) explains the problem with using a variable to access an array index. It's a security question.
If you allow a non validated input to be used as an array index, your application may crash. Even if you validate the index, it's a matter of time until you refactor the code and the validation be skipped. Hence the recommendation to avoid such code. One recommended solution is to use a Map: https://stackoverflow.com/a/44882765/4398050
If you don't wanna know about this problem, it is possible to ignore the issue in the codacy UI: https://support.codacy.com/hc/en-us/articles/207279979-Issues#2-remove-pattern
I can't figure out why the functions return is not being grabbed by “var”. I am using a select object to pass the parameter:
<select name="BILLTOSTATE" onchange="setBTS(this) >
<option value="Alabama">Alabama</option>
<option value="Alaska">Alaska</option>
ETC….
Function I would like to receive that value:
function setBTS(val){
var lv_bts = val.value;
return lv_bts;
}
And lastly the VAR I would like to set from setBTS function:
var lv_bts = setBTS();
Also I don’t know if it matters, but the new VAR lv_bts is located inside another function. Thanks. Sorry for this question. I'm new to this and I’m sure the answer is easy and in my face!
function setBTS takes a parameter as an argument, when you call it you would also need to supply that parameter in order to receive it back.
Think of it like this:
function myFunction(necessaryArgumentForFunction) {
let internalVariable = necessaryArgumentForFunction.value;
return internalVariable;
}
let variable = { value: 'some value' };
cont lv_bts = myFunction(variable);
console.log(lv_bts);
EDIT - (same day)
Add some details on question formatting in relation to thread below
When you are setting up a question either concisely explain anything you aren't showing or add code snippets.
For Example:
This method is being called by an event handler which is passing its state (this/event) in as an argument.
Or:
let ele = document.getElementById('myEle');
ele.onChange = setBTS;
Also a good idea to add any failed strategies you have attempted (with results) to save you and people trying to help some time
I personally also like to include any technologies I'm using that may be relevant with versions (eg Node v8.1.4, npm v5.3.0) sometimes it helps surface known issues or idiosyncracies that might not be immediately apparent if you aren't as familiar with the library.
Anyway, I hope that helps :D. Have a good one.
setBTS is expecting an argument; you aren't passing one.
setBTS(val) is expecting a parameter, which is not passed when you are calling the function, Hence val.value will be undefined since val is undefined
I've got an array, and it's got a method I threw onto it called add, which I use as a wrapper around push. I've found myself using push a few times when I should have used add, and now I'm thinking it would be nice to assign a reference to my add method to the array's native push. Thus, calling push on the array would call add.
Do internals depend on externally available native methods like push? How would this affect compatibility? Is this a bad idea? If so, why?
Some code:
PR.state = {
views: []
};
_.extend(PR.state.views, {
add: function(view) {
var parent = view.parent;
if ((!this.length && view instanceof PR.Views.App) || (parent && _.contains(this, parent)))
this.push(view);
}
});
// I am thinking:
PR.state.views.push = PR.state.views.add;
I would strongly advise against changing the behavior of a standard array method. If you really want a custom method, then just create a new method and give it it's own unique name and use that.
Changing the behavior of existing methods could have all sorts of bad consequences:
Incompatibility with code retrieved from any other source.
Creates a non-standard and unexpected implementation if anybody else ever works on this project. This is like adding in a time bomb to trip up some future developer.
Training yourself to use your own custom method instead of .push() is just something that a decent developer would do. Just do it.
Creating a newly named method with an appropriate and descriptive name improves the readability, understandability and maintainability of your code. Replacing an existing method with something that works differently does the opposite.
It's not so bad if you just replace the method on one instance of an array, not the whole array prototype, but it's still not a good idea.
What a stupid question. If I replace push with add, then what happens when I call push from add? :< :< I haven't tested it, but I suspect that while Array.prototype.push will still be available, unless I use Array.prototype.push explicitly, calling add will result in a mondo endless loop.
I'm currently in the process of building out a VERY simple Observer class for a project I'm working on. I have successfully implemented the subscribe, unsubscribe, and notify methods. Everything works exactly as expected when using "regular" functions (i.e: var f = function()).
However, when I pass an anonymous function to the subscribe method and then try to unsubscribe passing the "same" anonymous function it (as expected) doesn't remove the function from my array (they are different, after all).
Here's my subscribe and unsubscribe methods:
this._subscribers = {};
subscribe: function(type, callback) {
if ( isUndefined(this._subscribers[type]) ) {
this._subscribers[type] = [];
}
this._subscribers[type].push(callback);
},
unsubscribe: function(type, callback) {
if ( this._subscribers[type] instanceof Array ) {
var index = this._subscribers[type].indexOf(callback);
if ( index >= 0 ) {
this._subscribers[type].splice(index, 1);
}
}
},
And here's the code I'm testing with:
var o = new gaf.events.Observable();
o.subscribe('testEvent', function(event) { alert('Got It!'); });
o.notify('testEvent');
// Correct alerts 'Got It!'
o.unsubscribe('testEvent', function(event) { alert('Got It!'); });
o.notify('testEvent')
// Incorrectly alerts 'Got It!'
I know I could using an object (i.e.: _subscribers[event] = {}) and then when something subscribes I could add a new property equal to the callback and the value equal to the callback. This will cause Javascript to convert the callback to the string. I could then look it up (provided the methods passed in sub/unsub are exactly the same) using that string.
However, this is a mobile project and I'm very leery about storing strings that could be hundreds of characters long as properties as we could end up with a lot of subscribers.
Are there any other ways of doing this? Are there any SMALL (tiny, even) hashing libraries I can use to maybe hash the string value of the function and use that as the property? Would it be better to store the string value of the callback (so I can compare against it) in the array (rather then the actual callback) and use eval() on it?
EDIT
First, thanks all for the replies!
Per all the questions about "Why even pass anonymous" functions -
There really is no reason one COULDN'T use named functions. In fact, I agree with everyone that named functions are going to be the better solution. I'm simply gathering information and looking for a solution so that I can build out an implementation that handles the most scenarios as best as possible.
The other reason for this is what happens if a user (co-worker) of this Observable class passes it an anonymous function and then unsubscribes. That function won't actually be unsubscribed and therefore won't be cleaned up. I have a thing against orphaned data :)
Maybe another question I should as is, is it possible to test if the callback is anonymous or not? I'm going to assume no but doesn't hurt to ask.
There is nothing wrong with storing the entire string; premature optimization is evil.
However, this sounds like an incredibly bad idea.
If someone changes the function, but forgets to change the unsubscribed copy, the code will be subtly broken with no warning whatsoever.
Instead, you can require the user to store the anonymous function in a variable if they want to unsubscribe from it.
Alternatively, you can pass an optional name with each subscriber, then unsubscribe by that name.
the clients that use the Observer should store the reference to the function.
var obsCallback = function() {
}
o.subscribe('test', obsCallback);
....
o.unsubscribe('test', obsCallback);
in other words, keep a reference to the function around...
Perhaps a better solution is to modify the code using your library
var f = function() { alert('Got It!'); };
o.subscribe('testEvent', f);
o.notify('testEvent');
o.unsubscribe('testEvent', f);
o.notify('testEvent');
You could even return the function from the subscribe method
var f = o.subscribe('testEvent', function() { alert('Got It!'); });
// ...
then if you want to store a hash or some other identifier for subscribed functions, it is opaque to the calling code meaning that you just use the returned value to unsubscribe and the library hides the implementation detail.
What is the reason for passing in anonymous functions rather than named ones, or keeping references that you can use for unsubscribing later?
Alternatively you could allow for an optional 'id' argument but this would require unnecessarily complex bookkeeping to avoid duplicates.