tech

[English] [Japanese]

05. enum

In this article, we will discuss enum values in LuneScript.

enum

LuneScript enum allows you to name and manage a set of values.

The types of values that can be handled as an enum are as follows.

  • int
  • real
  • str

The range of one enum can be defined from multiple values, but the value types must be the same.

In other words, an enum with int values cannot define real or str values.

Definition method

An enum is defined like this:

// @lnsFront: ok
enum TestEnum {
  val0,
  val1,
  val2,
}
print( TestEnum.val0, TestEnum.val1, TestEnum.val2 );  // 0, 1, 2

In this example, we define val0, val1, val2 to be 0, 1, 2 respectively.

If you want to specify the values of the enum , define it like this:

// @lnsFront: ok
enum TestEnum {
  val0 = 10,
  val1,
  val2 = 20,
}
print( TestEnum.val0, TestEnum.val1, TestEnum.val2 ); // 10, 11, 20

If you omit enum values, assign values according to:

  • Assign a value that is 1 added to the previous enum value.
  • First enum value is 0

Note that when assigning a string to an enum value, the value cannot be omitted.

// @lnsFront: ok
enum TestEnum {
  val0 = "abc",
  val1 = "def",
  val2 = "ghi",
}
print( TestEnum.val0, TestEnum.val1, TestEnum.val2 ); // abc def ghi

An expression can be specified for the value to be set to the enum value. However, the expression must use only immediate values.

For example if:

// @lnsFront: error
fn func(): int {
  return 100;
}
enum TestEnum {
  val0,
  val1 = val0 + 10,  // 10
  val2 = func(),     // error
}

val = val0 + 10 can be specified because it uses an immediate value, but val2 = func() is an error because it is not an immediate value.

how to use

The defined enum can be used as a type as follows.

// @lnsFront: ok
enum TestEnum {
  val0,
  val1,
  val2,
}
fn func( val:TestEnum ): int {
   return val + 100;
}
print( func( TestEnum.val1 ) ); // 101

Here the argument val of func() is of TestEnum type. As a result, the argument val of func() can be an int with a limited range instead of a simple int.

If you specify an enum value, then enum type symbol.enum value symbol like TestEnum.val.

omission

Basically, to specify an enum value, it is enum type symbol.enum value symbol, but if you know that the type of the assignment destination is an enum type, you can omit enum symbol.

For example, in the following case, we know that the argument of func() is of type TestEnum , so we can specify it as .val1 instead of TestEnum.val1 .

// @lnsFront: ok
enum TestEnum {
  val0,
  val1,
  val2,
}
fn func( val:TestEnum ): int {
   return val + 100;
}
print( func( .val1 ) ); // 101

Note that if you omit the enum type defined in an external module, you must import that external module.

We'll talk about imports later.

Converting enum values

Enum values can be used as defined values as well as enum values.

You can see this in the val + 100 example above, where val is the enum value we defined in TestEnum, but it can also be 0, 1, or 2. (In the example above, we are passing val1, so it will be 1). So val + 100 is 1 + 100, resulting in 101.

On the other hand look at the following example.

// @lnsFront: error
enum TestEnum {
  val0,
  val1,
  val2,
}
fn func( val:TestEnum ): int {
   return val + 100;
}
let val = 1;
func( val ); // error

func( val ) in this example results in an error.

In this case, val is 1, and val1 is 1 in TestEnum, but the type of val is int, which is different from TestEnum, so an error occurs.

To convert the value of the type assigned to the enum value to the corresponding enum value, use the _from() function as follows.

// @lnsFront: ok
enum TestEnum {
  val0,
  val1,
  val2,
}
fn func( val:TestEnum ): int {
   return val + 100;
}
let val = 1;
func( unwrap TestEnum._from( val ) );

Here func( unwrap TestEnum._from( val ) ) gets the enum value TestEnum.val1 of TestEnum corresponding to val by TestEnum._from() and passes it to func().

I'll explain unwrap later.

enum value name

enum values assign values to symbols.

An enum value can get this symbol name dynamically by $_txt.

For example, TestEnum.val1 is output in the following case.

// @lnsFront: ok
enum TestEnum {
  val0,
  val1,
  val2,
}
fn func( val:TestEnum ) {
   print( val.$_txt ); 
}
func( .val1 ); // TestEnum.val1

By $_txt we get the symbolic name of the enum value.

$ is syntactic sugar for function calls, as we'll see later.

Notes on $_txt

$_txt has the following caveats:

"Undefined which enum value's symbolic name is returned by $_txt when there are multiple equivalent enum values"

For example, in the following case, it is undefined whether print() outputs TestEnum.val1 or TestEnum.val2.

// @lnsFront: ok
enum TestEnum {
  val0,
  val1 = 10,
  val2 = 10,
}
fn func( val:TestEnum ) {
   print( val.$_txt ); 
}
func( .val1 ); // TestEnum.???

Also, the string format obtained by $_txt may change in the future. Use =$_txt= only for log output, and do not write code that switches processing depending on the result of $_txt.

full enum value list

You can get a list of all enums defined by an enum with $_allList.

For example, for the following code:

// @lnsFront: ok
enum TestEnum {
  val0,
  val1,
  val2,
}
foreach val in TestEnum.$_allList {
   print( val.$_txt );
}

will output:

TestEnum.val0
TestEnum.val1
TestEnum.val2

algebraic data types

For enum types, you can group only one type of int, real, or str to limit the range of values, but you cannot group multiple types. Algebraic data types are a more general version of enum types and can group all types, not just int, real and str.

Details are explained in the next article.

../match

summary

By using an enum, you can easily define the range of values, and it provides a modern way to handle enums easily.

Next time, we'll talk about variables.