I have a map with (among other things) a long valu...
# javascript
h
I have a map with (among other things) a long value. Using the toString() method on the map, the long value comes out thus:
time=1548429717649
. But I am generating JSON, and am converting my map to an object before doing
JSON.stringify()
in order to avoid cyclic references from the map, and I see the long values represented as objects, and in the final JSON, they are represented thus:
"time":{"low_":-2053476207,"high_":360}
. I guess this has to do with dealing with 64bit numbers in javascript, but my question is: How do I detect this and how do I convert them? Using
typeof
as I pull them out of my map, I only get
object
...
g
You cannot have numbers bigger than 2^53 in json (just Number type)
So or you use default implementation or just convert number to string before serialization
I believe that ko need to detect, just use Long as type of field
s
You can use
x instanceof Kotlin.Long
to detect instance of Kotlin Long on JS side.
h
Well, I populate this in (the JS part of) an mpp like this:
Copy code
internal actual fun getTimeImpl(): Long = Date().getTime().toLong()
It gets compiled into this javascript code:
Copy code
function getTimeImpl() {
    return Kotlin.Long.fromNumber((new Date()).getTime());
}
And to convert from a map to a javascript object, I have this:
Copy code
internal fun mapToObject(map: Map<String, *>): dynamic {
    return js("""
        var toReturn = {};
        var i = map.entries.iterator();
        while (i.hasNext()) {
          var element = i.next();
          if (element.value.toNumber) {
              toReturn[element.key] = element.value.toNumber();
          } else {
              toReturn[element.key] = element.value;
          }
        }
        return toReturn;
    """
    )
}
... Oh wait!
2^53, @gildor? Not 2^63? So a regular Long doesn't fit in a JS number?
Anyway, I use the above
mapToObject
workaround and am satisfied for now.
g
@hallvard Correct, because JS doesn't have int or long, only Number which has floating point part, so max integer is 2^53
h
OK, thanks for clearing it up. Is my workaround OK, or do I run into unknown risks here?
s
@hallvard It depends on data you are working with. In general case: 1. You will lose precision when you converting very big (or very small) Longs. If you use Longs for stuff like hashes or money then it is probably not OK. 2. Values other than Long might have
toNumber
field, which you might not want to call. 3. It will miss `Long`s in nested structures like
mapOf("foo" to arrayOf(1L, 2L))
Also, it can be written in Kotlin:
Copy code
val toReturn = js("{}")
    for ((key, value) in map) {
       toReturn[key] = when(value) {
           is Long -> value.toDouble()
           else -> value
       } 
    }
    return toReturn
h
My next question would have been «how could I implement this in kotlin», but you beat me to it, @Svyatoslav Kuzmich [JB]. Brilliant, thanks!