Trying out immutable-js, I found something that I don't fully understand and want to make sure I'm using set correctly.
Basically, if you use "set()" to set a value of a property with an object or array, it stores a raw object/array, whereas if you use merge, it does what I'd expect, converting the raw array to an immutable list.
So my question is: Should you avoid using set() with objects/arrays for parameter 2?
Jasmine Test example here:
it("can do a thing you shouldn't do(?) - inject a normal object into a Map via set", function(){
const expected = fromJS({ a: [ 3, 4, 5 ] });
const set_value = expected.set("a", [3, 4,5]);
const merge_value = expected.merge({"a": [3, 4,5]});
expect(expected.get("a")).toEqualImmutable(set_value.get("a")); // Fails
expect(expected.get("a")).toEqualImmutable(merge_value.get("a")); // Passes
})
Output is:
Message:
Expected
List [ 3, 4, 5 ]
to equal
3,4,5
You should use set() with objects/arrays only when you want your Immutable objects to contain objects/arrays.
That is to say, this is a style choice without a definitive right answer.
A good rule of thumb is to not put mutable object into your immutable collections unless you know what you're doing and you have a really good reason to.
Is it safe?
That depends on what you mean by safe.
As of 4.0.0-rc8
getIn, setIn, updateIn, merge, toJS, etc. should all work with Immutable collections containing mutable data, so you're safe in that regard.
On the other hand, if you start putting mutable values in your immutable containers, you lose a lot of the benefits of having an immutable collection in the first place. You no longer have the guarantee that a reference to the same object will always contain the same data.
Related
I don't know if this is a problem that others get, but I have code in python that goes like this:
def makemove(board,move,val):
new=board
new[move[0]][move[1]]=val
return new
My problem is that if I use this function by simply doing makemove(game,[0,1],-1) where game equals [[0,0,1],[0,1,0],[1,0,0]] the variable game becomes [[0, -1, 1], [0, 1, 0], [1, 0, 0]].
I have tried to look into functions setting global variables, but I have thus for not found a way to prevent makemove() from setting the variables that you put into it. Is there something obvious that I'm missing?
You need to clone board.
import
new = copy.deepcopy(board)
see https://stackoverflow.com/a/2612815/93910 for other ways of doing this.
Your code sets elements of a variable which is a "reference".
In other words, your variable new is really an array reference to board, i.e. it points to the same memory location. So when you change new, the original variable board gets changed.
Here's another answer on how to think about this: https://stackoverflow.com/a/9697367/93910
This is basically because assignment in Python doesn't mean what you think it does, and lists are mutable sequences.
Lists are Python objects. The name board is merely a label for or reference to that object.
So when you say new=board this means "let the name new reference the same object as the name board".
In Python every object has a unique identifier that you can retrieve using id(). Let's create a board, do the assignment and see what happens:
In [1]: board = [[0,0,1],[0,1,0],[1,0,0]]
In [2]: new = board
In [3]: id(new), id(board)
Out[3]: (34495504136, 34495504136)
new and board are referencing the same object.
Since a list is a mutable sequence you can change it without getting an error.
So if you want to play with any mutable sequence inside a function without modifying the original, you should use copy.deepcopy first to make a copy and modify that.
So, I am using Immutable.js and had a normal Immutable.Map and had to switch up the object a little because it kept sorting the object when I didn't want it to (previously, I was using a hash, now as you see, an array). Even an OrderedMap didn't work, so I put the "new" object like so, and now of course, the obj retains its ordering. BUT, now I have to iterate thru it every time I want to get a specific ID. Seems wasteful, I was curious if there is a helper function in which I can just request a key (id), in this case, and get back the appropriate obj.
"sneakers": Immutable.List([
[{_id: 1, color: "red", price: 250}],
[{_id: 1638, color: 728, price: 90}]
etc...
so, if I wanted the obj in which the _id is 1638, I'd have to filter thru it. Previously I could just "getIn". Is there a quick way with Immutable.js given this data structure?
This is not the perfect solution, but if you have always one object inside inner array and all _id's are unique, you can use:
sneakers.find(function(data) {
return data.find(function(innerArr) {
return innerArr.get("_id") === 1638
})
}).get(0).toJS();
In this solution, you do not need to iterate all List, it returns when it finds first occurrence.
A small reminder: Immutable.List converts your list to immutable only for one level, inner array is still mutable. You should use fromJS() instead of List. My solution works for fromJS() usage.
I have Object parsed from JSON (haxe.Json.parse()) and I need to iterate over it.
I already tried to cast this object to Array<Dynamic>:
var data:String='{"data":{"0":0,"1":1},"method":"test"}';
var res:{method:String,data:Array<Dynamic>} = haxe.Json.parse(data);
for (n in res.data)
trace('aa')
There is no Can't iterate dynamic exception, just not working (iterating).
I completley don't understand why in Haxe iterating procedure is so difficult.
For the sake of posting a complete answer, and in case other people are wondering
In your first example, you've told the compiler that "res" contains two properties - one called "method" (which is a String) and one called "data" (which is Array). Now the JSON you're using doesn't actually have an Array<Dynamic>, it just has a dynamic object. An Array would look like: "data":[0,1].
So, assuming you meant for the JSON to have data as a Dynamic object, here is how you loop over it, using Reflect (as you mentioned in the comments):
var data:String='{"data":{"0":0,"1":1},"method":"test"}';
var res = haxe.Json.parse(data);
for (n in Reflect.fields(res.data))
trace(Reflect.field(res.data, n));
Note here we don't have to specify the type of "res", since we're using Reflection just leaving it as Dynamic will be fine.
Now, if your JSON actually contains an Array, the code might look like this:
var data:String='{"data":[0,1],"method":"test"}';
var res:{method:String,data:Array<Int>} = haxe.Json.parse(data);
for (n in res.data)
trace(n);
Here you use explicit typing to tell the compiler that res.data is an Array (and this time it actually is), and it can loop over it normally.
The reason you didn't get an error at compile-time is because the compiler thought there was genuinely going to be an array there, as you told it there was. At runtime, whether or not it throws an exception probably depends on the target... but you probably want to stay out of that anyway :)
Demo of both styles of code: http://try.haxe.org/#772A2
I'm working in Python here (which is actually pass-by-name, I think), but the idea is language-agnostic as long as method parameters behave similarly:
If I have a function like this:
def changefoo(source, destination):
destination["foo"] = source
return destination
and call it like so,
some_dict = {"foo": "bar"}
some_var = "a"
new_dict = changefoo(some_var, some_dict)
new_dict will be a modified version of some_dict, but some_dict will also be modified.
Assuming the mutable structure like the dict in my example will almost always be similarly small, and performance is not an issue (in application, I'm taking abstract objects and changing into SOAP requests for different services, where the SOAP request will take an order of magnitude longer than reformatting the data for each service), is this okay?
The destination in these functions (there are several, it's not just a utility function like in my example) will always be mutable, but I like to be explicit: the return value of a function represents the outcome of a deterministic computation on the parameters you passed in. I don't like using out parameters but there's not really a way around this in Python when passing mutable structures to a function. A couple options I've mulled over:
Copying the parameters that will be mutated, to preserve the original
I'd have to copy the parameters in every function where I mutate them, which seems cumbersome and like I'm just duplicating a lot. Plus I don't think I'll ever actually need the original, it just seems messy to return a reference to the mutated object I already had.
Just use it as an in/out parameter
I don't like this, it's not immediately obvious what the function is doing, and I think it's ugly.
Create a decorator which will automatically copy the parameters
Seems like overkill
So is what I'm doing okay? I feel like I'm hiding something, and a future programmer might think the original object is preserved based on the way I'm calling the functions (grabbing its result rather than relying on the fact that it mutates the original). But I also feel like any of the alternatives will be messy. Is there a more preferred way? Note that it's not really an option to add a mutator-style method to the class representing the abstract data due to the way the software works (I would have to add a method to translate that data structure into the corresponding SOAP structure for every service we send that data off too--currently the translation logic is in a separate package for each service)
If you have a lot of functions like this, I think your best bet is to write a little class that wraps the dict and modifies it in-place:
class DictMunger(object):
def __init__(self, original_dict):
self.original_dict = original_dict
def changefoo(source)
self.original_dict['foo'] = source
some_dict = {"foo": "bar"}
some_var = "a"
munger = DictMunger(some_dict)
munger.changefoo(some_var)
# ...
new_dict = munger.original_dict
Objects modifying themselves is generally expected and reads well.
I wonder if you think that there is a need to refactor this class.( regarding separation of concern)
publi class CSVLIstMapping<T>
{
void ReadMappingFromAttirbutes();
void GetDataFromList();
}
ReadMappingFromAttributes - Reads the mapping from the type T and stores it in the class. Has a name of the list to use and a number of csvMappingColumns which contains the name of the property to set the value in and the name of csvcolumns.
GetObjectsFromList - uses a CVSListreader ( which is passed in via the constructor) to get the data from all row's as KeyValuePair ( Key = csvcolumnName , value = actually value) and after that it uses the mappinginformation( listname and csvMappingColumns ) to set the data in the object.
I cant decide if this class has 2 concerns or one. First I felt that it had two and started to refactor out the conversion from rows to object to another object. But after this it felt awkward to use the functionality, as I first had to create a mappingretriver, and after that I had to retrive the rows and pass it in together with the mapping to the "mapper" to convert the objects from the rows
/w
Sounds like two concerns to me: parsing and mapping/binding. I'd separate them. CSV parsing should be a well-defined problem. And you should care about more than mere mapping. What about validation? If you parse a date string, don't you want to make sure that it's valid before you bind it to an object attribute? I think you should.
Rule of thumb: if it's awkward, it's wrong.
I have to say I'm finding it hard to understand what you've written there, but I think it's likely that you need to refactor the class: the names seem unclear, any method called GetFoo() should really not be returning void, and it may be possible that the whole ReadMappingFromAttribute should just be constructor logic.