4 ms·
> bigints are smaller and faster, with less footguns But be careful!! Javascript WILL interpret your bigints as Number() and round them down because they are t
by Fabricio20 4mo ago
> bigints are smaller and faster, with less footguns
But be careful!! Javascript WILL interpret your bigints as Number() and round them down because they are too big without telling you!!!
Famously seen by every snowflake user that has interacted with Javascript, quite an annoying problem.
- spiffytech 4mo agoFortunately we're seeing more JS DB libraries offering to read large numbers as the BigInt type.
- shakna 4mo agoBut frustratingly, a JS BigInt is nothing like a BigInt in any other language. In JS - BigInt is 64bit integer. In anything else - BigInt is a arbitrarily large integer.
- anematode 4mo agoHm? JavaScript BigInts are arbitrary precision, and you need to use methods like BigInt.asIntN(64, a) to convert them to 64 bits
- mort96 4mo agoI hate this so much because you can’t nicely serialise a BigInt as JSON. Using a string is nicer but it only makes sense where int64 is used as an ID, not where it’s used as a number; and you don’t wanna have to configure this per field per query.
- nh2 4mo agoJSON has arbitrary length numbers in the spec only.
- mort96 4mo agoCompletely and utterly irrelevant.
- sheept 4mo agoYou can serialize a BigInt by specifying a replacer: const obj = { a: 9007199254740993n } JSON.stringify(obj, (_key, value) => typeof value === 'bigint' ? JSON.rawJSON(value.toString()) : value)
- mort96 4mo agoAnd then you end up with strings on the other side, not numbers.
- sheept 4mo agoNo you don't? The example I gave produces {"a":9007199254740993} not {"a":"9007199254740993"}
- mort96 4mo agoOh, that's much worse! The JSON string `{"a":9007199254740993}` decodes to the object `{"a":9007199254740992}` with typical JSON parsers like JavaScript's `JSON.parse`.
- sheept 4mo agoIf you're applying a replacer, then you'd supply a reviver when parsing: const json = '{ "a": 9007199254740993 }' JSON.parse(json, (_key, value, context) => /^\d+$/.test(context.source) ? BigInt(context.source) : value)
- mort96 4mo agoYeah but now you have the world's biggest foot gun in your API.
- marcosdumay 4mo agoIMO, I'm tending toward thinking that having types on your readable serialization format is a mistake, and that they should be always input to the (de)serializer instead.
- Etheryte 4mo agoThis is simply not true? Or maybe I misunderstand what you mean?
- paulddraper 4mo ago!! Node.js drivers will correctly read int64 as string or bigint, not number. E.g. pg for PostgreSQL Maybe there’s a buggy driver but I don’t know it.
- Fabricio20 4mo agoBrowser!! The browser reads it as Number. If your rest api returns {"id": 1324535222364012585} for example, javascript will try and parse that as number from the response!!! You can of course, change the api such that it does {"id": "1324535222364012585"} instead and voila, it will no longer try parsing it as number. Or the many other workarounds people have recommended above (like appending a prefix, or using a different encoding), but why is it trying to parse a number thats too big and instead of throwing it just rounds down without telling you????!
- paulddraper 4mo agoHuh? The subject was database drivers. You seem to be talking about JSON. (Which technically has no limit on number size or precision, but in practice is float64.)
- silvestrov 4mo agoGood trick is to prefix all such keys with magic, i.e. a couple of letters that identify type type of key. Then it will always be a string and you will be free to change the format/type of the key in the future to UUID or whatever you like.
- zmj 4mo agoRule of thumb: if you’re not doing math with a value, it’s not a number.
- myko 4mo agoI've been preaching this for years but nobody believes me until it bites them in the ass
- klysm 4mo agoIndexes?
- throw-the-towel 4mo agoSpeaking of which, one of my favourite UX brainfarts is treating text fields where you enter a sum as numbers. Why, you ask? Let's you have a number like 10,000 and you want to replace it with 20,000. You delete the leading 1, and boom! The number is now zero, and three of the digits are gone, and you'll have to retype them like you got no other things to do with your life.
- sheept 4mo agoThis can be avoided by supplying a reviver: const json = '{ "a": 9007199254740993 }' JSON.parse(json, (_key, value, context) => /^\d+$/.test(context.source) ? BigInt(context.source) : value)
- Piezoid 4mo agoUsing a Feistel cipher and base 32 encoding at the boundaries of the system can help catching vibe coded edge code that attempt to decode identifiers in javascript. It also somewhat obfuscate the cardinalities and fill rate of the tables.
- Terr_ 4mo ago> Javascript WILL interpret your bigints as Number() A similar horror story from PHP, which I discovered by diagnosing a test failure. (Or maybe it was in production? Long ago, can't remember.) I think the code in question was for some kind of web auth, comparing random 32-character hexadecimal strings. PHP has a "feature" where its == operator falls back to trying certain strings as numbers... and that includes a version with scientific notation. (12000 == "12000" == "12e3") Such a collision through bad comparison may seem unlikely, but there are two islands of higher odds: 0*10^X is zero for any X, and X*10^0 is one for any X. Finally, leading zeros can be included. ("0e1234" == "00000e1" and "1234e0" == "9e0000") The fix was simply going to stricter ===, but it definitely reinforced my dislike of "loose" languages.