Reorganize. Add null & error docs

master
Araozu 2024-03-16 09:30:32 -05:00
parent 1e63e799ce
commit 893b43e099
9 changed files with 176 additions and 38 deletions

View File

@ -1,11 +0,0 @@
# Sets
```thp
// Set[Int]
val ages = Set(30, 31, 33, 35)
for age in ages {
print("{age}")
}
```

View File

@ -8,7 +8,7 @@ Use square brackets as usual.
val fruits = ["apple", "banana", "cherry"]
val apple = fruits[0]
print(apple)
print(apple) // apple
var numbers = [0, 1, 2, 3]

View File

@ -1,4 +1,4 @@
# Union types
# Enums (Tagged unions)
## Basic enums
@ -27,22 +27,22 @@ enum IpAddress
val addr_1 = IpAddress::V4("192.168.0.1")
match addr_1
| IpAddress::V4(ip)
case IpAddress::V4(ip)
{
// code..
}
| IpAddress::V6(ip)
case IpAddress::V6(ip)
{
// more code..
}
// Without the full qualifier
match addr_1
| ::V4(ip)
case ::V4(ip)
{
// code...
}
| ::V6(ip)
case ::V6(ip)
{
// even more code...
}

View File

@ -34,10 +34,18 @@ var Person mary_jane = .{
To access the fields of a map we use square braces `[]`.
```thp
mary_jane[age] += 1
print(mary_jane[name]) // Mary
mary_jane["age"] += 1
print(mary_jane["name"]) // Mary
```
Or dot access `.` if the field's name is a valid identifier.
```thp
mary_jane.age += 1
print(mary_jane.name)
```
## Anonymous maps
An anonymous map allows us to store and retrieve any key of any datatype.
@ -69,26 +77,39 @@ We can freely assign fields to an anonymous map:
```thp
// Modify an existing field
car[year] = 2015
car["year"] = 2015
// Create a new field
car[status] = "used"
car["status"] = "used"
```
However, if we try to access a field of an anonymous map we'll get an error.
However, if we try to access a field of an anonymous map we'll get
a nullable type, and we must annotate it.
```thp
print(car[status]) // Error: Can't access a field of an anonymous map
// This is ok, we are declaring what datatype we expect
String? car_status = car["status"]
// This won't work, the compiler doesn't know what datatype to use
var car_status = car["status"]
```
Instead, we should use the `get` function of the map, which expects a
datatype and returns an Option
Instead, we can use the `get` function of the map, which expects a
datatype and returns that type as nullable
```thp
// | this function
String? car_status = car.get[String]("status")
val car_status = car.get[String]("status")
```
The `get` function will check that a key `"status"` exists in the map,
Both ways to get a value will check that the key exists in the map,
and that it has the correct datatype. If either the key doesn't exist
or it has a different datatype, it will return `None`.
or it has a different datatype, it will return `null`.
We can also use dynamic keys, following the same rules:
```thp
val generated_value = "key"
String? v = map[generated_value]
// or
val v = map[String](generated_value)
```

View File

@ -0,0 +1,82 @@
# Nullable types
All datatypes in THP disallow the usage of `null` by default.
To represent `null` we must use nullable types, represented
by the question mark `?` character.
For instance, a POST request may have a `username` parameter,
or it may not. This can be represented with an `String?`.
```thp
String? new_username = POST::get("username")
```
When we have a `Type?` we cannot use it directly. We must first
check if the value is null, and then use it.
```thp
if new_username != null {
// Here `new_username` is automatically casted to String
}
```
We must check explicitly that the value is not null. Doing
`if new_username {}` alone is not allowed.
## Usage
To create a nullable type we must explicitly annotate the type.
```thp
val favorite_color = null // Error, we must define the type
String? favorite_color = null // Ok
```
Other examples:
```thp
fun get_first(Array[String?] values) -> String? {}
val result = get_first([])
```
## Optional chaining
If you have a `Type?` and you wish to access a field of `Type` if it exists,
you can use the optional chaining operator.
```thp
Person? person = ...
val name = person?.name
```
- If `person` is null, `person?.name` will return `null`
- If `person` is not null, `person?.name` will return `name`
## Elvis operator
The Elvis operator `??` is used to give a default value in case a `null` is found.
```thp
// This is a function that may return a Int
fun get_score() -> Int? {...}
val test_score = get_score() ?? 0
```
For the above code:
- If `get_score()` is not null, `??` will return `get_score()`
- If `get_score()` *is* null, `??` will return `0`
You can use the Elvis operator to return early
```thp
val username = get_username() ?? return
```

View File

@ -0,0 +1,44 @@
# Try expressions
```thp
fun get_value() -> Result[Int, String] { ... }
// treating errors as normal enums
val result = match get_value()
case Ok(result) { result }
case Err(error) { return error }
// get the value if Ok, otherwise re-throw
val result = try get_value()
// get the value if Ok, return a new value otherwise
val result = try get_value() return Err("new error")
// get the value if Ok, assign a new value otherwise
Int result = try get_value() else 20
// get the value if Ok, otherwise run block with the error value
val result = try get_value()
with error
{
// handle error
}
fun throws_exception() -> Result[Int, MyException|MyOtherException] { ... }
val result = try throws_exception() catch
case MyException(e)
{
// deal with MyException
}
case MyOtherException(e)
{
// deal with MyOtherException
}
```

View File

@ -26,8 +26,8 @@ children:
path: loops
- name: Match
path: match
- name: Collections
path: collections
- name: Data structures
path: data-structures
children:
- name: Tuples
path: tuples
@ -35,8 +35,8 @@ children:
path: arrays
- name: Maps
path: maps
- name: Sets
path: sets
- name: Enums
path: enums
- name: Functions
path: functions
children:
@ -48,11 +48,13 @@ children:
path: higher-order
- name: Lambdas
path: lambdas
- name: ADTs
path: adts
- name: Error handling
path: error-handling
children:
- name: Union types
path: union-types
- name: Nullable types
path: "null"
- name: Try expressions
path: try
- name: Classes
path: classes
children:

View File

@ -59,7 +59,7 @@
</g>
</svg>
<div class="h-1"></div>
<pre style="padding: 0 !important;">
<pre style="padding: 0 !important; border: none !important;">
<code class="language-thp">
fun find_person(Str person_id) -> Result[Str] {
val person_id = try person_id.parse[Int]()