Note: I am using Nodejs which may or may not have subtle differences from vanilla ECMAscript's standards.
I have always heard that when using a for-each loop to iterate over the properties of an object, I should not count on the properties being in the same order. (even though in practice I have never seen a case where the objects were iterated over in a different order). In production, we have what I believe to be a typo where an object is created with an overwritten property.
var obj = {
a: 'a property',
b: 'another property',
c: 'yet another property',
a: 'woah we have another a?'
}
In Nodejs, am I guaranteed that the second a property containing the string 'woah we have another a?' will ALWAYS shadow the first a property containing the string 'a property'?
(even though in practice I have never seen a case where the objects were iterated over in a different order)
The following should give you a different order in V8 atleast.
var obj = {
"first":"first",
"2":"2",
"34":"34",
"1":"1",
"second":"second"
};
for (var i in obj) { console.log(i); };
// Order listed:
// "1"
// "2"
// "34"
// "first"
// "second"
As discussed here
ECMA-262 does not specify enumeration order. The de facto standard is to match
insertion order, which V8 also does, but with one exception:
V8 gives no guarantees on the enumeration order for array indices (i.e., a property
name that can be parsed as a 32-bit unsigned integer).
Remembering the insertion order for array indices would incur significant memory
overhead.
Though the above says the enumeration order is not specified but that is after the object is created. I think we can safely assume that insertion order should remain consistent, as there is no point for any engine to do otherwise and alter the insertion order.
var obj = {
"first":"first",
"2":"2",
"34":"34",
"1":"1",
"second":"second",
2: "two"
};
// gives result
{ '1': '1',
'2': 'two',
'34': '34',
first: 'first',
second: 'second' }
Related
I was trying to make an interface and initialize its instance with another object properties by spread syntax.
I found something weird and wanted to find out why this can happen.
This is an example of what I want.
A: The object that I want to make as a result
A = { a: number, b: number, c: number, d: number }
B: The object I've got with DB query
B = {a: number,b: number,c: number,e: string}
C: The object that has a value I will insert manually
C = { d: boolean }
So I've declared an interface A, and used spread syntax to make an object of A with B object.
A_object = {...B_object }
What I expected was an object of A which has properties 'a', 'b', and 'c', or an error.
But the result was quite different.
Property 'e' also appeared, which doesn't exist in interface A.
Can anybody explain why this happens?
The spread operator is a JavaScript feature which does not know about the known properties of TypeScript-interfaces. All properties of B_object will therefore appear in A_object when A_object = { ...B_object }.
From a type-safety perspective, this is fine. Everything needed to construct a valid A instance is also present in B, so spreading B into A is considered to be valid.
You are probably looking for excess property checks. Those are not necessarily needed in a structural type system and there are only a select few places where TypeScript does perform them. And spreading objects is not one of those places. There is an open Issue requesting this and you can give it a thumbs up if you want to see it implemented.
This strange behavior baffles me. I intend to create a dictionary with a single array field. Then within this array, two extra sub dictionaries are appended. Here is code,
var dictionary = [String: Any]()
var array = [[String: Any]]()
dictionary["array"] = array
var dict1:[String:Any] = ["abc": 123, "def": true]
var dict2:[String:Any] = ["111": 1.2345, "222": "hello"]
array.append(dict1)
array.append(dict2)
Debugger output.
As you can see from the debugger output, the var array is updated successfully (with 2 sub dictionaries appended). But the dictionary["array"] still has 0 value.
It appears the (dictionary["array"]) and (array) are two separate objects
Yes, they are separate. The element dictionary["array"] is an immutable value of type Array<_> because it's added as a value type to the dictionary not a reference type.
If you tried to add dict1 to the array by addressing the element via it's encapsulating dictionary like this:
(dictionary["array"] as! Array).append(dict1)
You would see an error like this:
error: cannot use mutating member on immutable value of type 'Array<_>'
From the Swift Language docs, emphasis added:
A value type is a type whose value is copied when it is assigned to a variable or constant, or when it is passed to a function.
You’ve actually been using value types extensively throughout the previous chapters. In fact, all of the basic types in Swift—integers, floating-point numbers, Booleans, strings, arrays and dictionaries—are value types, and are implemented as structures behind the scenes.
I've noticed that if we insert an object {a: 1, b: 2, c: 3}, in database it'll be stored as {c: 3, b:2, a: 1}. Why is MongooseJS doing this?
Is it for Performance Gain (or) some other logic?
Could anyone please explain this to me in detail?
There is no such thing as properties order in object. If the order is important for you use an array.
The for...in statement iterates over the enumerable properties of an object, in original insertion order. For each distinct property [...]
However this seems to be implementation (browser) dependant.
In objects you can't rely on order of the properties as even various iteration methods may give various results.
Ordering of properties in objects is complex, as this answer explains: https://stackoverflow.com/a/38218582/893780
Even though it's not specified in the standard, normal property keys are stored in insertion order.
Internally, Mongoose uses a faster code path when cloning objects, that reverses the property order. It basically does this:
let oldObject = { a: 1, b: 2, c: 3 };
let newObject = {};
let keys = Object.keys(oldObject);
let i = keys.length;
while (i--) {
let k = keys[i];
let val = oldObject[k];
newObject[k] = val;
}
Because normal keys are stored in insertion order, newObject will be the reverse of oldObject:
{ c: 3, b: 2, a: 1 }
However, because this can cause issues in queries, Mongoose added an option retainKeyOrder to prevent this reversal.
However, according to the same answer that I linked to above, you still can't rely on any order being imposed when using Object.keys() or for..in.
I'm currently trying to implement my own DynamicArray data type in Swift. To do so I'm using pointers a bit. As my root I'm using an UnsafeMutablePointer of a generic type T:
struct DynamicArray<T> {
private var root: UnsafeMutablePointer<T> = nil
private var capacity = 0 {
didSet {
//...
}
}
//...
init(capacity: Int) {
root = UnsafeMutablePointer<T>.alloc(capacity)
self.capacity = capacity
}
init(count: Int, repeatedValue: T) {
self.init(capacity: count)
for index in 0..<count {
(root + index).memory = repeatedValue
}
self.count = count
}
//...
}
Now as you can see I've also implemented a capacity property which tells me how much memory is currently allocated for root. Accordingly one can create an instance of DynamicArray using the init(capacity:) initializer, which allocates the appropriate amount of memory, and sets the capacity property.
But then I also implemented the init(count:repeatedValue:) initializer, which first allocates the needed memory using init(capacity: count). It then sets each segment in that part of memory to the repeatedValue.
When using the init(count:repeatedValue:) initializer with number types like Int, Double, or Float it works perfectly fine. Then using Character, or String though it crashes. It doesn't crash consistently though, but actually works sometimes, as can be seen here, by compiling a few times.
var a = DynamicArray<Character>(count: 5, repeatedValue: "A")
println(a.description) //prints [A, A, A, A, A]
//crashes most of the time
var b = DynamicArray<Int>(count: 5, repeatedValue: 1)
println(a.description) //prints [1, 1, 1, 1, 1]
//works consistently
Why is this happening? Does it have to do with String and Character holding values of different length?
Update #1:
Now #AirspeedVelocity addressed the problem with init(count:repeatedValue:). The DynamicArray contains another initializer though, which at first worked in a similar fashion as init(count:repeatedValue:). I changed it to work, as #AirspeedVelocity described for init(count:repeatedValue:) though:
init<C: CollectionType where C.Generator.Element == T, C.Index.Distance == Int>(collection: C) {
let collectionCount = countElements(collection)
self.init(capacity: collectionCount)
root.initializeFrom(collection)
count = collectionCount
}
I'm using the initializeFrom(source:) method as described here. And since collection conforms to CollectionType it should work fine.
I'm now getting this error though:
<stdin>:144:29: error: missing argument for parameter 'count' in call
root.initializeFrom(collection)
^
Is this just a misleading error message again?
Yes, chances are this doesn’t crash with basic inert types like integers but does with strings or arrays because they are more complex and allocate memory for themselves on creation/destruction.
The reason it’s crashing is that UnsafeMutablePointer memory needs to be initialized before it’s used (and similarly, needs to de-inited with destroy before it is deallocated).
So instead of assigning to the memory property, you should use the initialize method:
for index in 0..<count {
(root + index).initialize(repeatedValue)
}
Since initializing from another collection of values is so common, there’s another version of initialize that takes one. You could use that in conjunction with another helper struct, Repeat, that is a collection of the same value repeated multiple times:
init(count: Int, repeatedValue: T) {
self.init(capacity: count)
root.initializeFrom(Repeat(count: count, repeatedValue: repeatedValue))
self.count = count
}
However, there’s something else you need to be aware of which is that this code is currently inevitably going to leak memory. The reason being, you will need to destroy the contents and dealloc the pointed-to memory at some point before your DynamicArray struct is destroyed, otherwise you’ll leak. Since you can’t have a deinit in a struct, only a class, this won’t be possible to do automatically (this is assuming you aren’t expecting users of your array to do this themselves manually before it goes out of scope).
Additionally, if you want to implement value semantics (as with Array and String) via copy-on-write, you’ll also need a way of detecting if your internal buffer is being referenced multiple times. Take a look at ManagedBufferPointer to see a class that handles this for you.
i learned about tuples today, in a nutshell they allow you to store several values, an example of tupel is
let exampleTuple = (exampleString: "This", exampleInt: 1)
And we can easily access any value of a tuple with a dot notation, for example:
exampleTuple.exampleString
To me this seems extremely similar to objects holding certain information, I might be missing something or not understanding tuples completely, therefore I'm asking for an explanation on when we should use tuples or objects?
According to the book on Swift,
Tuples are useful for temporary groups of related values. They are not suited to the creation of complex data structures.
They define "temporary" through the scope of the data: if a piece of data never leaves the scope of a single method, or a group of methods of the same object, it can be considered temporary, even though it might very well persist through the lifetime of an application.
If your data structure is useful outside a temporary scope - for example, because it needs to be returned from a public method of your class, model it as a class or structure, rather than as a tuple.
Another important consideration is associating behavior with your data: if your object needs to have methods, use classes for them. Use tuples only for data devoid of behavior.
Tuples are heavily used in Python and it seems to me they have mostly the same purpose in Swift. Think of it as a quick way to deliver multiple values from one point to another. An example that shows up in the Swift book and a pattern that is used in Python very often is returning an HTTP status code and a text body from a method:
func greeting() {
return (200, "Hello World")
}
...
let (status, body) = greeting()
if 200 == status {
println(body)
}
else if status >= 400 {
println("Error \(status): \(body)")
}
Of course this is just one use case, but I think it gets the point across. A built-in example is the function enumerate(), which returns a tuple of (index, value):
for (idx, val) in enumerate(["a", "b", "c"]) {
println("Index \(idx): \(val)")
}