I was looking at:
hash_1 = Hash[*[Array("a".."j"), Array(1..10)].transpose.flatten]
So I thought, the return with or without the splat, "*", looks the same - so why
hash_1 = Hash[[Array("a".."j"), Array(1..10)].transpose.flatten] returns {} ?
Hence when I tested
Array(1..10).equal? [*Array(1..10)] => false
Thus
Hash[Array(1..10)] => {}
Hash[*Array(1..10)] => {1=>2, 3=>4, 5=>6, 7=>8, 9=>10}
Please help.
Documentation for Ruby Hash's [] method says you can provide 1) pairs of values which will be used as keys and values, 2) an array of key-value pairs in the form of subarrays, or 3) an object which is convertible to a hash. Hash[*Array(1..10)] with the splat matches the first case, and a quick experiment in irb will show:
irb(main):001:0> Hash.new([1,2])
=> {}
which produces a Hash with a default value of [1,2] but containing no elements. That's what gets passed as the hashable object when you use Hash[Array(1..10)], i.e., without the splat.
As of Ruby 2.4 you get the following warning:
irb(main):002:0> Hash[[1,2]]
(irb):2: warning: wrong element type Integer at 0 (expected array)
(irb):2: warning: ignoring wrong elements is deprecated, remove them explicitly
(irb):2: warning: this causes ArgumentError in the next release
(irb):2: warning: wrong element type Integer at 1 (expected array)
(irb):2: warning: ignoring wrong elements is deprecated, remove them explicitly
(irb):2: warning: this causes ArgumentError in the next release
Hash[]
Hash[] expects an even number of arguments (or one single hash-like argument) :
Hash['a','b']
# {"a"=>"b"}
but
Hash[['a','b']]
# {}
In the second example, there's only one argument : an array with two strings, which doesn't answer to_hash. Depending on the Ruby version, it will display a warning or raise an ArgumentError.
Hash[] with splat
For your example :
Hash[*Array(1..10)]
is the same as :
Hash[1,2,3,4,5,6,7,8,9,10]
# {1=>2, 3=>4, 5=>6, 7=>8, 9=>10}
It's an even number of arguments, so a Hash can be created out of every pair.
Note that with an odd number of arguments :
Hash[1,2,3,4,5,6,7,8,9]
# ArgumentError: odd number of arguments for Hash
There is another problem with your code, or rather with your exploratory test, that wasn't mentioned in the other answers so far:
BasicObject#equal? is true IF AND ONLY IF the argument is the same object as the receiver. Not "an object with the same value", not "an object with the same representation", only if it is the exact same object. In other words, for equal? to be true, there is only one single object involved which is both the receiver and the argument. In your case, there are two objects (even though they have the same value and the same representation), so equal? can never ever return true.
You should not use equal?. It is one of the basic tenets of object-oriented programming that objects can simulate other objects (in fact, OO was invented in a language for simulations), but equal? allows you to distinguish between the real object and its simulation, and thus it breaks OO. I repeat: testing for reference equality makes your code non-OO. Frankly, it shouldn't even be possible in a "true" OO language, and it makes me sad that Ruby has it (although Java is worse, in Java it is even the default equality behavior).
You should (almost) always use ==, which is semantic value equality. In some rare cases, you can use eql? (strict value equality). In the Ruby core libraries and standard libraries itself, eql? is only used together with hash for hash- and set-like behavior. (In fact, the only three places I can think of, where eql? is used in Ruby, is Hash, Set (and SortedSet), and the set-like array operations (Array#uniq, Array#uniq!, Array#&, Array#|, and Array#-).) Never use equal?.
Note: === is a different beast altogether and has nothing to do with equality. (It is kind of an unfortunate name to use three equals signs for something that is not equality.)
Related
In javascript, does getting a length of a number type array vs. custom object type array take the same time?
First array has elements of type number. Second has custom type something like this but not limited to:
ISomeType: {
e1: string,
e2: ISomeOtherType,
..
e16: number
}
Thanks a lot
This is more a JavaScript question than a TypeScript question, since it's about runtime behavior.
No, there's no difference in the speed of reading the length property. It's just a property of the array object (an "own" property, not inherited), exactly the same in both cases.
Slightly tangential, but: Setting the length of an array could theoretically have surprising time characteristics. Array objects are "exotic" objects (ones that don't behave like normal objects) and one of the ways they're exotic is that although length is defined as a data property (not an accessor property with getter and setter methods), setting it has a side effect: If you set it so that some elements in the array will no longer be in the array, the properties for those elements are removed. Here's an example:
const a = ["a", "b", "c"];
console.log(a.length); // 3
console.log(a[2]); // c
a.length = 1; // Removes the "b" and "c" elements
console.log(a.length); // 1
console.log(a[2]); // undefined
In theory, then, if you have a really, really big array (say, millions of elements) and you set length such that you're removing a lot of elements from the array, you'd see a larger delay than if you did that with a small array where you were removing only a few elements. But you'd have to have a truly massive array, and JavaScript engines could optimize the process (for instance, not really removing the properties, but instead checking later on retrieval whether they should still exist).
Recently I found out that Ruby doesn't optimize [] and {} to be interned to point to a common shared object. Demo:
irb(main):001:0> [].object_id
=> 70284401361960
irb(main):002:0> [].object_id
=> 70284392762340 # different
irb(main):003:0> [].object_id
=> 70284124310100 # different
irb(main):005:0> {}.object_id
=> 70284392857480
irb(main):006:0> {}.object_id
=> 70284392870480 # different
irb(main):007:0> {}.object_id
=> 70284392904360 # different
I understand that often empty hashes and array literals are used to initialize values that will be immediately mutated. But this happens even if you do [].freeze.object_id or {}.freeze.object_id instead.
Contrast this with String, when the env var RUBYOPT is set to --enable-frozen-string-literal:
irb(main):001:0> ""
=> 70284400947400
irb(main):002:0> ""
=> 70284400947400 # same
irb(main):003:0> ""
=> 70284400947400 # same
Even you don't enable frozen string literals, if you call "".freeze.object_id instead, you'll get the same object id each time, though I suspect that initial "" literal is still allocated an intermediate string object that freeze is being called on.
In a performance-sensitive codebase (well, as performance-sensitive you can allow yourself to be while still using MRI lol) I've seen this workaround, which uses the following shared constants instead of [] or {} for cases when the hash or array doesn't need to be mutable:
module LessAllocations
EMPTY_HASH = {}.freeze
EMPTY_ARRAY = [].freeze
# String literals are already frozen, use '' instead
# EMPTY_STRING = ''
end
So my questions are:
Is this a missed optimization opportunity?
It seems like a peephole optimization could be written to intern frozen empty hash or array literals. Would need to be part of the language's semantics, i.e. would there be any observable differences, (obviously besides the behavior of object_id)?
Are empty hash and array literals represented by tagged pointers? Do they even cause any allocation to happen?
Is this a missed optimization opportunity?
To answer this question one would to have to do a survey of real world memory usage, but I believe it is unlikely. You could perform a little experiment...
class Array
EMPTY_ARRAY = [].freeze
def freeze
empty? ? EMPTY_ARRAY : super
end
end
Empty objects are very small. Having so many that they use significant memory compared to everything else your program is using memory for is an edge case.
I understand that often empty hashes and array literals are used to initialize values that will be immediately mutated.
For that reason, adding copy-on-write to empty hashes and arrays might slow things down.
But this happens even if you do [].freeze.object_id or
{}.freeze.object_id instead.
Freezing them means you know ahead of time they will remain empty, that's extremely rare. Having so many known empty hashes and arrays that it becomes a performance issue is an edge case. The constant work-around seems fine.
The one with colorsArray.last works but not the one with the subscript syntax, e.g., colorsArray[2]. Any help you can give me with understanding this would be great. I'm learning Swift on my own so I come here to get my questions answered.
let colorsArray = ["Red", "Green", "Blue"]
if let method2 = colorsArray.last {
print(method2)
}
if let method2 = colorsArray[2] {
print(method2)
}
The issue is that with an array, the subscript operator does not return an optional, so it makes no sense to use an unwrapping construct like if let to unwrap it.
Try let foo = colorsArray[42], where the index is out of bounds. It doesn’t return nil, but rather will just crash with an “subscript out of range” error. As the documentation says (emphasis added):
Use the first and last properties for safe access to the value of the array’s first and last elements. If the array is empty, these properties are nil.
...
You can access individual array elements through a subscript. The first element of a nonempty array is always at index zero. You can subscript an array with any integer from zero up to, but not including, the count of the array. Using a negative number or an index equal to or greater than count triggers a runtime error.
So, the last provides safe access, returning an optional, but the subscript operator doesn’t return an optional, but also doesn’t provide safe access if you supply an invalid index.
If you will go to the documentation, you will find that when you use the Api last, the return type is optional, hence you can use optional binding to safely unwrap the value. But if you access the element by index like you are doing in the second case will give you the unwrapped value and compiler assumes that there will be a value for sure if you access like that. But keep in mind if your array size is less than the index you are passing then you may get error of array index out of bounds.
Unlike last the result of subscribing an array by index is not an optional.
let method2 = colorsArray[2]
print(method2)
The reason is most likely the ObjC compatibility, the disadvantage is if the index doesn't exist it throws an exception aka it crashes.
I'm working with the JSON API format, which has the notion of a data property which can hold either a scalar (single) or array (multiple) value. I'm writing code for encoding and decoding into the format, and when naming my types, was trying to come up with a good name for such types of values. In TypeScript, it would be
type Poly<T> = T | T[];
For your information, here is the relevant part of the JSON API doc (my emphasis):
Primary data MUST be either:
a single resource object, a single resource identifier object, or null, for requests that target single resources
an array of resource objects, an array of resource identifier objects, or an empty array ([]), for requests that target resource collections
As an example, here is a mapping function for such mutant values:
function polymap<T, U>(data: Poly<T>, fn: (input: T) => U, thisArg?: any): Poly<U> {
if (data instanceof Array) return (data as T[]).map(fn, thisArg);
return fn.call(thisArg, data as T);
}
Anyway, as you can see, I'm going with "poly", but is there any established terminology for this, or other good suggestions?
First, the difference between scalars and arrays isn't the number of elements, it's the dimensionality.
Scalars are arrays. Specifically, they're 0-dimensional arrays. So you'd just call all of them arrays.
But note that usually the focus isn't on what values the variable can hold, but what operations are allowed on the variable's potential values.
Some operations can generalize from 1 element to N elements, which seems to be what you want.
The CS-y term for this kind of operation is a "vectorizing operation".
The math term for this kind of operation is a "lifting operation".
I've never heard of anything like this and judging from the fact that the available JSON data types shown here
http://www.tutorialspoint.com/json/json_data_types.htm do not mention anything related to such a data type, I'm betting that this is just smoke and mirrors implemented behind the scenes.
Scalar values and arrays are structured very differently. Combining the two into a true data type would be self contradicting. I'm betting that when the variable is instantiated a method is called somewhere to check the value for an array or scalar value, at which point one of two things takes place. 1- The data type is automatically set as an array and if a scalar is given, it is converted to an array of length 1 and whenever it is called behind the scenes an array is being accessed at index 0. Or 2- The behind the scenes method checks what the data type that was passed in is and sets the same data type for the variable given before instantiation actually takes place.
If a MonoPoly Mohn-O-Pohl-E (if you will because I can't find anything else to call it and it looks like Monopoly) was a scalar and is set to an array data type at some point, the old value can be destroyed and a new one assigned with the same name but as an array. This can happen vise versa and all this can be done behind the scenes as well, making this data type appear to house the description of a scalar along with an array.
is there any established terminology for this, or other good
suggestions?
I'm going to ignore "established terminology", and likely "good" as well, and make the following suggestions on a linguistic basis. My personal choice, due to its sense of one or more rungs and its being the latin origin of scalar, would be:
ladder
Another possible noun:
assemblage
Like constant, I think the following adjectives are ripe to become nouns:
inconstant (similar to incontinent, "insufficient voluntary control" which seem to be what you described you have over this API issue.)
transferable
indiscrete (nicely homophonic to indiscreet)
dual-purpose
multipurpose (the adjective our schools love)
This might even be an oportunity to coin a new word:
polyunary
versutility (my second favorite)
Such functionality is likely replacing a scalar with an array when another element is "added" to a slot. AFAIK there's no term for this, so the question seems more like an English language question.
Try these:
elastic scalar
expandable scalar
scarray (scalar/array)
scalarray (another portmanteau)
arrayable
tardis (holds more than it appears to)
Which is better way to declare Array and Dictionary, I have used both:
Array<String>
[String]
For me [String] is very fast in terms of coding but in reality how both are different in terms of compiler and performance and which one we should follow?
From iOS Developer Library on Swift...
The type of a Swift array is written in full as Array< Element >, where
Element is the type of values the array is allowed to store. You can
also write the type of an array in shorthand form as [Element].
Although the two forms are functionally identical, the shorthand form
is preferred and is used throughout this guide when referring to the
type of an array.
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html
The two are equivalent.
From Apple
Array Type Shorthand Syntax
The type of a Swift array is written in full as Array, where Element is the type of values the array is allowed to store. You can also write the type of an array in shorthand form as [Element]. Although the two forms are functionally identical, the shorthand form is preferred and is used throughout this guide when referring to the type of an array.
I would note one difference is that if you are trying to instantiate an array of objects where you need to specify the module (because of naming collisions) the shorthand form appears to choke.
let array1 = [MyModule.MyClass]() // Compile error: Invalid use of '()' to call a value of non-function type '[MyClass.Type]'
let array2 = Array<MyModule.MyClass>() // Works as expected.
Other situations like optional unwrapping or as parameter typing work using shorthand notation. I only have tried in Swift 2.3