What is the F# equivalent of this C#:
const MyEnum None = (MyEnum)1;
This does not work:
[<Literal>]
let None : MyEnum = enum 1 //ERROR: not a valid constant expression
although, curiously, it's okay in an attribute constructor:
[<MyAttribute(enum 1)>]
type T = class end
The discrepancy seems odd.
This is fixed in v3.1 and works as expected.
To hold the value of each constant you need to have an instance variable (generally, private). You cannot create an object of an enum explicitly so, you need to add a parameterized constructor to initialize the value(s). The initialization should be done only once.
An enumeration is a data type that consists of a set of named values that represent integral constants, known as enumeration constants. An enumeration is also referred to as an enumerated type because you must list (enumerate) each of the values in creating a name for each of them.
You can use the name() method to get the name of any Enum constants. The string literal used to write enum constants is their name. Similarly, the values() method can be used to get an array of all Enum constants from an Enum type.
Each enum type has a corresponding integral type called the underlying type of the enum type. This underlying type shall be able to represent all the enumerator values defined in the enumeration. If the enum_base is present, it explicitly declares the underlying type.
I believe the observed compiler behavior is intentional and completely in line with restrictions for values having [<Literal>]
attribute defined by F# Language Spec $10.2.2:
The right-hand side expression must be a literal constant expression that is made up of either:
- A simple constant expression, with the exception of (), native integer literals, unsigned native integer literals, byte array literals, BigInteger literals , and user-defined numeric literals. —OR—
- A reference to another literal
Consider
type MyEnum =
| Case1 = 1
| Case2 = 2
then
[<Literal>]
let Valid: MyEnum = MyEnum.Case1 // Literal enumeration case on the right
will happily compile, but
[<Literal>]
let Invalid: MyEnum = enum<MyEnum>(1) // Expression on the right
// generating constant value, which
// potentially might be completely off
// legit MyEnum cases
will not, although outside of [<Literal>]
context both statements will compile into absolutely identical IL.
Assuming that [<Literal>]
attribute is the only F# way of making C# const
equivalent the only option for defining enumeration literal value would be using a literal enumeration case of proper type on the right side of let
.
The discrepancy is caused by the fact that C# (MyEnum)0
is indeed a literal, but F# enum
is a function of type int32 -> 'T
.
I believe it would not be difficult for F# team to add special processing for this construct, but unfortunately it is not there yet.
Nevertheless, there is one way to accomplish what you need, but only for 0
value:
type MyEnum =
| None = 0
| Foo = 1
[<Literal>]
let X = MyEnum()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With