{"id":15878510,"url":"https://github.com/tdd/proposal-numeric-underscores","last_synced_at":"2025-04-01T23:43:12.190Z","repository":{"id":66918311,"uuid":"90566882","full_name":"tdd/proposal-numeric-underscores","owner":"tdd","description":"A syntax upgrade proposal for numeric literals in JS (ES262)","archived":false,"fork":false,"pushed_at":"2017-07-10T13:41:46.000Z","size":2,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-07T15:30:51.290Z","etag":null,"topics":["esnext","javascript","js","readability","syntax"],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tdd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-05-07T22:52:53.000Z","updated_at":"2024-02-14T15:59:51.000Z","dependencies_parsed_at":"2023-05-20T16:30:58.829Z","dependency_job_id":null,"html_url":"https://github.com/tdd/proposal-numeric-underscores","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdd%2Fproposal-numeric-underscores","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdd%2Fproposal-numeric-underscores/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdd%2Fproposal-numeric-underscores/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tdd%2Fproposal-numeric-underscores/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tdd","download_url":"https://codeload.github.com/tdd/proposal-numeric-underscores/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246730312,"owners_count":20824396,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["esnext","javascript","js","readability","syntax"],"created_at":"2024-10-06T02:40:19.847Z","updated_at":"2025-04-01T23:43:12.168Z","avatar_url":"https://github.com/tdd.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# This proposal lives somewhere else now\n\nIt's been merged with the **accepted proposal led by Sam Goto**, which [you can find here](https://github.com/tc39/proposal-numeric-separator). Contribute there!\n\n# Motivation\n\nLarge numeric literals are difficult for the human eye to parse quickly, especially when there are long digit repetitions.  This impairs both the ability to get the correct value / order of magnitude…\n\n```js\n1000000000   // Is this a billion? a hundred millions? Ten millions?\n101475938.38 // what scale is this? what power of 10?\n```\n\n…but also fails to convey some use-case information, such as fixed-point arithmetic using integers.  For instance, financial computations often work in 4- to 6-digit fixed-point arithmetics, but even storing amounts as cents is not immediately obvious without separators in literals:\n\n```js\nconst FEE = 12300\n// is this 12,300? Or 123, because it's in cents?\n\nconst AMOUNT = 1234500\n// is this 1,234,500? Or cents, hence 12,345? Or financial, 4-fixed 123.45?\n```\n\nUsing underscores (`_`, U+005F) as separators helps improve readability for numeric literals, both integers and floating-point (and in JS, it's all floating-point anyway):\n\n```ruby\n1_000_000_000      # Ah, so a billion\n101_475_938.38     # And this is hundreds of millions\n\nFEE = 123_00       # $123 (12300 cents, apparently)\nFEE = 12_300       # $12,300 (woah, that fee!)\nAMOUNT = 12345_00  # 12,345 (1234500 cents, apparently)\nAMOUNT = 123_4500  # 123.45 (4-fixed financial)\nAMOUNT = 1_234_500 # 1,234,500\n```\n\nAlso, this works on the fractional and exponent parts, too:\n\n```ruby\n0.000_001 # 1 millionth\n1e10_000  # 1^10000 -- granted, far less useful / in-range…\n```\n\nThis would make a very valuable addition to literal syntax.\n\n# Prior art\n\nUnderscores are allowed anywhere in integer and floating-point literals in the following languages (at least):\n\n- Ruby\n- Python 3.6+\n- Java 7+\n- Rust\n- Swift\n\nSo yes, C++, C# and Go don't have it (yet), but that still seems like JS is missing out here.\n\n# Syntax changes\n\n(Changes expressed over ES2016's spec text.)\n\nThe only section of lexical grammar that seems impacted would be numeric literals, specifically digit definitions:\n\n## 11.8.3 Numeric Literals\n\n```\nDecimalDigit:: one of\n  0 1 2 3 4 5 6 7 8 9 _\n\nBinaryDigit:: one of\n  0 1 _\n\nOctalDigit:: one of\n  0 1 2 3 4 5 6 7 _\n\nHexDigit:: one of\n  0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F _\n```\n\n# Cross-cutting concerns\n\nMost number-testing and number-conversion APIs and procedural steps are likely affected, usually automatically by transitivity of abstract operations used in their algorithms, in order to maintain consistency.\n\n## *ToNumber*, *ToXx* and the `Number` constructor\n\nThe semantics described in *7.1.3.1. ToNumber Applied to the String Type* already rely on digit definitions from 11.8.3, so the algorithm there doesn't seem to need any adjustment.\n\nBecause the `Number` constructor (as described in 20.1.1.1), various abstract operations (such as *ToInteger*, *ToIntXx* and *ToUintXx*) and most other \"standard lib\" operations rely on *ToNumber* semantics, they also do not seem to need adjustment.\n\n## Global object functions `isFinite` and `isNaN`\n\nBoth rely on *ToNumber* semantics (18.2.2 and 18.2.3), so they adjust automatically.\n\n## Global object functions `parseInt` and `parseFloat`\n\n`parseFloat` relies on *StrDecimalLiteral* syntax, which in turns relies on *DecimalDigit*, so we're covered.\n\n`parseInt` uses conventional radix prefixes, which we don't need to change, then delegates to *ToInt32*, which as seen above relies on our adjusted syntax definitions already.\n\n## Methods of the `Number` constructor\n\nAll detection methods (`isXx` methods) operate on actual numbers, such as number literals, so they do not introduce extra conversion / parsing rules.  The `parseFloat` and `parseInt` methods are just convenience aliases over their homonyms in the global object.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftdd%2Fproposal-numeric-underscores","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftdd%2Fproposal-numeric-underscores","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftdd%2Fproposal-numeric-underscores/lists"}