-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
180 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
# Enums | ||
|
||
TL;DR: | ||
|
||
```python | ||
import "stdlib/io.jou" | ||
|
||
enum Foo: | ||
Bar | ||
Baz | ||
|
||
def main() -> int: | ||
thing = Foo::Bar | ||
|
||
if thing == Foo::Bar: | ||
printf("It's bar\n") # Output: It's bar | ||
elif thing == Foo::Baz: | ||
printf("It's baz\n") | ||
else: | ||
assert False # never happens | ||
|
||
printf("%d\n", Foo::Bar as int) # Output: 0 | ||
printf("%d\n", Foo::Baz as int) # Output: 1 | ||
|
||
return 0 | ||
``` | ||
|
||
|
||
## Introduction | ||
|
||
Let's say you are working on a calculator program, | ||
and you have something like this: | ||
|
||
```python | ||
import "stdlib/io.jou" | ||
|
||
def calculate(a: double, b: double, op: byte) -> double: | ||
if op == '+': | ||
return a + b | ||
elif op == '-': | ||
return a - b | ||
elif op == '*': | ||
return a * b | ||
else: | ||
assert False # unsupported operation | ||
|
||
def main() -> int: | ||
printf("%f\n", calculate(1, 2, '+')) # Output: 3.000000 | ||
return 0 | ||
``` | ||
|
||
Here `assert False` aborts the execution of the program | ||
with an error message that contains the file name and line number. | ||
This is useful when some part of the code should never run. | ||
Here, if you leave it out, you will get a compiler warning, | ||
because then the `calculate()` function doesn't return a value in all cases. | ||
|
||
Now, suppose you need to add a division feature to the calculator. | ||
The most common ways to do division are: | ||
- "Normal" division: `7 / 3 = 2.33333...` | ||
- Floor division: `7 / 3 = 2` (result rounded down) | ||
|
||
It is tempting to use the `'/'` byte for normal division, but which byte to use for floor division? | ||
Maybe `'f'` for floor? | ||
If you ask any experienced programmer, they will probably tell you to use enums. | ||
Here's how it works in Jou: | ||
|
||
```python | ||
import "stdlib/io.jou" | ||
import "stdlib/math.jou" | ||
|
||
enum Operation: | ||
Add | ||
Subtract | ||
Multiply | ||
Divide # 7 / 3 produces 2.3333... | ||
FloorDivide # 7 / 3 produces 2 | ||
|
||
def calculate(a: double, b: double, op: Operation) -> double: | ||
if op == Operation::Add: | ||
return a + b | ||
if op == Operation::Subtract: | ||
return a - b | ||
if op == Operation::Multiply: | ||
return a * b | ||
if op == Operation::Divide: | ||
return a / b | ||
if op == Operation::FloorDivide: | ||
return floor(a / b) | ||
else: | ||
assert False # not possible | ||
|
||
def main() -> int: | ||
printf("%f\n", calculate(7, 3, Operation::Divide)) # Output: 2.333333 | ||
printf("%f\n", calculate(7, 3, Operation::FloorDivide)) # Output: 2.000000 | ||
return 0 | ||
``` | ||
|
||
Here `enum Operation` defines a new enum, which has 5 possible values. | ||
You can then use `if` statements to check which value an instance of `Operation` is. | ||
|
||
Enums members are accessed with `::` instead of `.`, | ||
because it was easier to implement in the Jou compiler. | ||
Please create an issue on GitHub if you would prefer `.` syntax instead. | ||
|
||
|
||
## Integer conversions | ||
|
||
Jou enums are actually just fancy integers. | ||
You can use `as` to convert them to integers and back: | ||
|
||
```python | ||
import "stdlib/io.jou" | ||
|
||
enum Operation: | ||
Add | ||
Subtract | ||
Multiply | ||
|
||
def main() -> int: | ||
printf("%d\n", Operation::Add as int) # Output: 0 | ||
printf("%d\n", Operation::Subtract as int) # Output: 1 | ||
printf("%d\n", Operation::Multiply as int) # Output: 2 | ||
return 0 | ||
``` | ||
|
||
This is sometimes used to assign a string to each enum member: | ||
|
||
```python | ||
import "stdlib/io.jou" | ||
|
||
enum Operation: | ||
Add | ||
Subtract | ||
Multiply | ||
|
||
def main() -> int: | ||
descriptions = ["Add numbers", "Subtract numbers", "Multiply numbers"] | ||
printf("%s\n", descriptions[Operation::Subtract as int]) # Output: Subtract numbers | ||
return 0 | ||
``` | ||
|
||
You can also convert integers to enums, | ||
but note that the result might not correspond with any member of the enum: | ||
|
||
```python | ||
import "stdlib/io.jou" | ||
|
||
enum Operation: | ||
Add | ||
Subtract | ||
Multiply | ||
|
||
def main() -> int: | ||
wat = 7 as Operation | ||
|
||
# Output: something else 7 | ||
if wat == Operation::Add: | ||
printf("Add\n") | ||
elif wat == Operation::Subtract: | ||
printf("Subtract\n") | ||
elif wat == Operation::Multiply: | ||
printf("Multiply\n") | ||
else: | ||
printf("something else %d\n", wat) | ||
|
||
return 0 | ||
``` | ||
|
||
Note that the `printf()` function sees the enum as if it was an integer, | ||
so you don't need to do `wat as int` when printing the integer value with `%d`. | ||
|
||
|
||
## Debugging | ||
|
||
Unfortunately, it is not possible to print the name of an enum member at runtime. | ||
You can however print its numeric value with printf's `%d` specifier (see above). | ||
Please create an issue on GitHub to discuss this if this annoys you. | ||
|
||
|