fslang-suggestions icon indicating copy to clipboard operation
fslang-suggestions copied to clipboard

Decimal, nativeint and unativeint literals

Open Happypig375 opened this issue 5 years ago • 5 comments

Decimal, nativeint and unativeint literals

I propose we allow decimal, nativeint and unativeint literals.

The existing way of approaching this problem in F# is (none).

C# 9 now has native-sized integers. Together with decimal constants, C# 9 can now define three types of literals that F# cannot. To interface with them, we must be able to interpret and define decimal, nativeint and unativeint literals.

let [<Literal>] Decimal = 3m
let [<Literal>] NativeInt = 3n
let [<Literal>] UNativeInt = 3un
match 3n with NativeInt -> true | _ -> false // true

Pros and Cons

The advantages of making this adjustment to F# are

  1. Consistency between numeric types - all other numeric types can be defined as literals. Why not these three?
  2. Increased interoperability with C#
  3. More code reuse - more chances to refactor constant patterns in `match's into literals that can be changed easily

The disadvantages of making this adjustment to F# are none that I can think of.

Extra information

Estimated cost (XS, S, M, L, XL, XXL): S

Related suggestions: https://github.com/fsharp/fslang-suggestions/issues/562

Affidavit (please submit!)

Please tick this by placing a cross in the box:

  • [x] This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
  • [x] I have searched both open and closed suggestions on this site and believe this is not a duplicate
  • [x] This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.

Please tick all that apply:

  • [x] This is not a breaking change to the F# language design
  • [x] I or my company would be willing to help implement and/or test this

Happypig375 avatar Mar 10 '20 05:03 Happypig375

Marked this approved-in-principle

dsyme avatar May 28 '20 22:05 dsyme

One minor suggestion, the name "unativeint" looks a bit like "un-native int" to me. Consider "NativeUInt"?

yatli avatar May 29 '20 01:05 yatli

What is expected in terms of codegen for a decimal literal? Existing types supported by the literal attribute are generated as static literals directly in the IL, e.g. for

[<Literal>]
let lit01 = 35

we generate

.field public static literal int32 lit01 = int32(0x00000023)

But decimal requires the initialization of a System.Decimal object.

esbenbjerre avatar Sep 18 '24 10:09 esbenbjerre

But decimal requires the initialization of a System.Decimal object.

Yes, in case of const, it should be done via attribute and initonly value:

 .field public static initonly valuetype [System.Runtime]System.Decimal dconst
 // Value:
 .custom instance void [System.Runtime]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(uint8, uint8, uint32, uint32, uint32) = (01 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00)

Additionally, there's a ldsfld+stsfld is generated in the cctor:

.method private hidebysig specialname rtspecialname static void .cctor () cil managed 
{
    IL_0000: ldsfld valuetype [System.Runtime]System.Decimal [System.Runtime]System.Decimal::One
    IL_0005: stsfld valuetype [System.Runtime]System.Decimal Constants::dconst
    IL_000a: ret
}

for public const decimal dconst = 1;

vzarytovskii avatar Sep 18 '24 12:09 vzarytovskii