The design suggestion Underscores in numeric literals after prefix and before suffix, Extend custom numeric types to support floating point literals and Hexadecimal, octal and binary custom numeric literals has been marked "approved in principle".
This RFC covers the detailed proposal for this suggestion.
- Suggestion: Underscores in numeric literals after prefix and before suffix, Extend custom numeric types to support floating point literals and Hexadecimal, octal and binary custom numeric literals
- Approved in principle
- Implementation
- Design Review Meeting(s) with @dsyme and others invitees
- Discussion
This RFC will allow the following things:
- Underscores in numeric literals after prefix and before suffix like
0x_1
or1_l
or mixed them up like0x_1_l
. - Hexadecimal, octal, binary and floating point custom numeric literals like
0x1I
or1.0G
Make the language more consistent and easier to read. Enhance the custom numeric literals feature by supporting not only integers but also floats.
-
Underscores can now be placed after prefix (
0x
,0o
,0b
) and before suffix (eg.UL
,y
,m
,f
). These are forbidden previously.let pi1 = 3_.1415F // Invalid cannot put underscores adjacent to a decimal point let pi2 = 3._1415F // Invalid cannot put underscores adjacent to a decimal point let socialSecurityNumber1 = 999_99_9999_L // OK (Invalid *previously*) let x1 = _52 // This is an identifier, not a numeric literal let x2 = 5_2 // OK (decimal literal) let x3 = 52_ // Invalid cannot put underscores at the end of a literal let x4 = 5_______2 // OK (decimal literal) let x5 = 0_x52 // Invalid cannot put underscores in the 0x radix prefix let x6 = 0x_52 // OK (Invalid *previously*) let x7 = 0x5_2 // OK (hexadecimal literal) let x8 = 0x52_ // Invalid cannot put underscores at the end of a number // In contrast to Java, literals with leading zeros are decimal in F#. let x9 = 0_52 // OK (decimal literal) let x10 = 05_2 // OK (decimal literal) let x11 = 052_ // Invalid cannot put underscores at the end of a number // To create an octal literal, prefix it with '0o' similar to hexadezimal literals. The same rules apply: let x12 = 0_o52 // Invalid cannot put underscores in the 0o radix prefix let x13 = 0o_52 // OK (Invalid *previously*) let x14 = 0o5_2 // OK (octal literal) let x15 = 0o52_ // Invalid cannot put underscores at the end of a number
-
Allow number prefix (
0x
,0o
,0b
) before integer custom numeric literals.let x1 = 0x123I // big int (291) let x2 = 0o123I // big int (83) let x3 = 0b1010I // big int (10)
The number prefix will not be removed from the string sended to the
FromString
of the numeric literal module. This may be a break change.module NumericLiteralG = let FromString s = s let x4 = 0x_99_9999_9999_9999_9999G // x4 will be "0x999999999999999999"
-
Allow floating point custom numeric literals.
This will require the numeric literal module contains two new functions:
val FromFloat: float -> 'CustomNumber val FromFloatString: string -> 'CustomNumber
According to this comment,
- When the literal has <= 15 significant figures1 and its exponent is within -300 to 300, the compiler will call
FromFloat
with the parsedfloat
number - Or the compiler will call
FromFloatString
with the original string
module NumericLiteralG = let FromFloat (s: float) = s let FromFloatString (s: string) = s let x1 = 123.456e-10G // x1: float = 1.23456e-08 let x2 = 123.456789123456789123e-10G // x2: string = "123.456789123456789123e-10"
- When the literal has <= 15 significant figures1 and its exponent is within -300 to 300, the compiler will call
-
Custom numeric literals module might harder to write.
-
May introduce break change.
- For number prefix (
0x
,0o
,0b
) before integer custom numeric literals, we might introduce a newFromIntegerString
to avoid the break change. - Or firstly parse it to
bigint
thenToString
to obtain a literal without prefix.
Please address all necessary compatibility questions:
-
Is this a breaking change? Maybe
-
What happens when previous versions of the F# compiler encounter this design addition as source code? Can write numeric literal module with new functions in the source code, but cannot use these new numeric literal grammar.
-
What happens when previous versions of the F# compiler encounter this design addition in compiled binaries? Cannot use the new numeric literal grammar.
Please list the reasonable expectations for tooling for this feature, including any of these:
-
Colorization
Might need to change the color schema of the numeric literals.
- Should we introduce a new
FromIntegerString
or use any way to remove number prefix from custom integer literal string passed toFromString
?
Footnotes
-
The first none zero figure to last none zero figure, without the dot. Can be match by the Regex:
↩^-?0*(?<number>\d+\.?\d*?)0*(?:$|[eE][+-]?(?<exp>\d+))