Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow simple arithmetic in number literals #539

Closed
5 of 6 tasks
rmunn opened this issue Feb 15, 2017 · 16 comments
Closed
5 of 6 tasks

Allow simple arithmetic in number literals #539

rmunn opened this issue Feb 15, 2017 · 16 comments

Comments

@rmunn
Copy link

rmunn commented Feb 15, 2017

I'm actually surprised that this hasn't been proposed before (or if it has, I wasn't able to turn it up with multiple searches). I propose we allow the following to compile:

let [<Literal>] a = 1
let [<Literal>] b = a + 1 // Equivalent to "let [<Literal>] b = 2"
let [<Literal>] c = a + b // Equivalent to "let [<Literal>] c = 3"

In addition, I'd like to see other basic arithmetic operators supported, like -, *, / and % (which might only be allowed for positive integers). Finally, it might also be nice to support bit-shift operators >>> and <<<, as well as bitwise operators like &&& and |||. E.g.,

let [<Literal>] bitShift = 4
let [<Literal>] multiplier = 1 <<< bitShift
let [<Literal>] bitMask = multiplier - 1

The existing way of approaching this problem in F# is to simply specify each of these values as a single number:

let [<Literal>] bitShift = 4
let [<Literal>] multiplier = 16
let [<Literal>] bitMask = 15

However, this runs the risk of the constant values, which are supposed to relate to each other, getting out of sync. It would be preferable to be able to change the bitShift constant to 5 and have the multiplier and bitMask constants automatically become 32 and 31 respectively. That would allow declaring bitShift at the top of the source file, and declaring multiplier and bitMask much closer to where they're used. With the current syntax requirements for literals, it's necessary to declare multiplier and bitMask near the top along with the bitShift value, so that if anyone changes bitShift later, they'll remember to change the other two related constants at the same time.

Pros and Cons

The advantages of making this adjustment to F# are being able to more clearly express the intent behind numeric literals that should be related to each other, and being able to change all of them with a single code change.

The disadvantages of making this adjustment to F# are that the compiler would have to keep track of previously evaluated literal names, so that it could use them in evaluating subsequent literals.

Extra information

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

Related suggestions: #129 might be related. That one was declined because there's a way to implement it with type providers; however, I can see no obvious way to implement this suggestion with type providers.

Affidavit (must be submitted)

Please tick this by placing a cross in the box:

  • This is not a question (e.g. like one you might ask on Stack Overflow) and I have searched Stack Overflow for discussions of this issue
  • I have searched both open and closed suggestions on this site and believe this is not a duplicate
  • 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:

  • This is not a breaking change to the F# language design
  • I would be willing to help implement and/or test this
  • I or my company would be willing to help crowdfund F# Software Foundation members to work on this
@smoothdeveloper
Copy link
Contributor

I was surprised I couldn't use <<< in my enums definition, +1 for this suggestion 🙂

@dsyme
Copy link
Collaborator

dsyme commented Mar 3, 2017

@rmunn Marking this approved in principle

@dsyme
Copy link
Collaborator

dsyme commented Mar 3, 2017

@rmunn It would be great if you could work with the community to submit an RFC and implementation in the F# 4.2 timeframe (whatever that turns out to be :) )

Thanks!

@rmunn
Copy link
Author

rmunn commented Mar 23, 2017

I've had a lot on my plate but I haven't forgotten this. I hope to get an RFC submitted sometime within the next month.

@dsyme dsyme added the needs rfc label Dec 1, 2017
@jwosty
Copy link
Contributor

jwosty commented Mar 23, 2018

Would this feature carry over to attributes and other situations where we use literals; not only applying to let [<Literal>] bindings? In the #beginners slack channel, MR.TaNk asked:

I'm trying to do something like that>

[<TestCase(773UL * 2UL, 27UL)>]
member __.``step count of number`` number stepCount =

[sic] But compiler doesn't let me * as constant expression. Is there a way, to say it's inlined/somehow constantinized.

@auduchinok
Copy link

An additional case to what @jwosty has mentioned is converting literal expressions to enums:

let [<Literal>] someValue = 1

[<AttributeWithSomeEnum(enum (someValue + 1))>]
do ()

It's possible to do this in C#, and I've stumbled upon this and had to introduce another named literal, which isn't good since the referenced literal may change without changing the extra literal:

let [<Literal>] LayerSyntaxPlusOne = 3001 // HighlighterLayer.ADDITIONAL_SYNTAX + 1

@En3Tho
Copy link

En3Tho commented Aug 26, 2022

Can someone write an RFC for this please? :D
I see some of the operations (+,-,*) are already implemented and hidden under ALLOW_ARITHMETIC_OPS_IN_LITERAL_EXPRESSIONS_AND_ATTRIBUTE_ARGS flag. They can be just used as templates for other operations (<<<, >>>, &&&, /, %, neg) etc

@En3Tho
Copy link

En3Tho commented Aug 26, 2022

This could be a nice addition to F#, especially when working with Enums. F# 7.1 maybe? But we need a hero.

@cartermp
Copy link
Member

Any RFC takers --> I'll gladly review 😄

@kerams
Copy link

kerams commented Nov 22, 2022

@dsyme, does the approval extend to support for arithmetics in enum definitions?

type E =
    | A = 1 <<< 0
    | B = 1 <<< 1
    | C = 1 <<< 2

@En3Tho, good spot. I wonder why that flag exists. Perhaps it could just be removed (so that we always allow arithmetics) and new operators added?

@kerams
Copy link

kerams commented Nov 22, 2022

fsharp/fslang-design#723

@kerams
Copy link

kerams commented Jan 22, 2023

This is done.

@vzarytovskii
Copy link

Should probably move RFC to preview

@Tarmil
Copy link

Tarmil commented Jan 22, 2023

Does the implementation cover all literals (such as [<Literal>] values)? Or just enum definitions?

@vzarytovskii
Copy link

Does the implementation cover all literals (such as [<Literal>] values)? Or just enum definitions?

Both

dotnet/fsharp#14370
dotnet/fsharp#14464

@kerams
Copy link

kerams commented Jan 22, 2023

fsharp/fslang-design#724 could incidentally do with merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants