Change syntax for null/errors
This commit is contained in:
parent
8b3f4a88c1
commit
a476fffe2c
Binary file not shown.
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 48 KiB |
@ -11,19 +11,29 @@ 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?`.
|
||||
or it may not. This can be represented with an `?String`.
|
||||
|
||||
<Code thpcode={`
|
||||
String? new_username = POST::get("username")
|
||||
?String new_username = POST::get("username")
|
||||
`} />
|
||||
|
||||
When we have a `Type?` we cannot use it directly. We must first
|
||||
When we have a `?Type` we cannot use it directly. We must first
|
||||
check if the value is null, and then use it.
|
||||
|
||||
The syntax `?` returns `true` if the value is not null.
|
||||
|
||||
<Code thpcode={`
|
||||
if new_username != null {
|
||||
if new_username?
|
||||
{
|
||||
// Here \`new_username\` is automatically casted to String
|
||||
}
|
||||
|
||||
// you can also manually check for null
|
||||
if new_username == null
|
||||
{
|
||||
// This is the same as above
|
||||
}
|
||||
|
||||
`} />
|
||||
|
||||
We must check explicitly that the value is not null. Doing
|
||||
@ -36,24 +46,24 @@ To create a nullable type we must explicitly annotate the type.
|
||||
<Code thpcode={`
|
||||
val favorite_color = null // Error, we must define the type
|
||||
|
||||
String? favorite_color = null // Ok
|
||||
?String favorite_color = null // Ok
|
||||
`} />
|
||||
|
||||
Other examples:
|
||||
|
||||
<Code thpcode={`
|
||||
fun get_first(Array[String?] values) -> String? {}
|
||||
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.
|
||||
If you have a `?Type` and you wish to access a field of `Type` if it exists,
|
||||
you can use the optional chaining operator `?.`.
|
||||
|
||||
<Code thpcode={`
|
||||
Person? person = ...
|
||||
?Person person = ...
|
||||
|
||||
val name = person?.name
|
||||
`} />
|
||||
@ -62,13 +72,41 @@ val name = person?.name
|
||||
- If `person` is not null, `person?.name` will return `name`
|
||||
|
||||
|
||||
## Null unboxing
|
||||
|
||||
The `!!` operator transforms a `?Type` into `Type`.
|
||||
|
||||
If you are sure that a value cannot be `null`, you can force the
|
||||
compiler to treat it as a regular value with the `!!` operator.
|
||||
Note the two exclamation marks.
|
||||
|
||||
<Code thpcode={`
|
||||
?String lastname = find_lastname()
|
||||
|
||||
// Tell the compiler trust me,
|
||||
// I know this is not null
|
||||
String s = lastname!!
|
||||
`} />
|
||||
|
||||
You can use it to chain access:
|
||||
|
||||
<Code thpcode={`
|
||||
val children_lastname = person!!.child!!.lastname
|
||||
`} />
|
||||
|
||||
However, if at runtime you use `!!` on a null value,
|
||||
the null value will be returned and your program will
|
||||
blow up later. So make sure to use this operator
|
||||
only when you are sure a value cannot be null.
|
||||
|
||||
|
||||
## Elvis operator
|
||||
|
||||
The Elvis operator `??` is used to give a default value in case a `null` is found.
|
||||
|
||||
<Code thpcode={`
|
||||
// This is a function that may return a Int
|
||||
fun get_score() -> Int? {...}
|
||||
fun get_score() -> ?Int {...}
|
||||
|
||||
val test_score = get_score() ?? 0
|
||||
`} />
|
||||
|
@ -12,14 +12,14 @@ and handled.
|
||||
|
||||
## Declare that a function returns an exception
|
||||
|
||||
To declare a possible error return value the `Result` enum
|
||||
is used.
|
||||
Possible errors have their own syntax: `Error!Type`.
|
||||
This means: This may be an `Error`, or a `Type`.
|
||||
|
||||
For example, a function that returned a `DivisionByZero`
|
||||
may be written like this:
|
||||
|
||||
<Code thpcode={`
|
||||
fun invert(Int number) -> Int!DivisionByZero
|
||||
fun invert(Int number) -> DivisionByZero!Int
|
||||
{
|
||||
if number == 0
|
||||
{
|
||||
@ -30,25 +30,22 @@ fun invert(Int number) -> Int!DivisionByZero
|
||||
}
|
||||
`} />
|
||||
|
||||
In the previous segment, `Int!DivisionByZero` denotates
|
||||
that the function may return either an `Int` or an `DivisionByZero`.
|
||||
In the previous segment, `DivisionByZero!Int` denotates
|
||||
that the function may return either a `DivisionByZero` error
|
||||
or an `Int`.
|
||||
|
||||
We then can return the error or success value;
|
||||
There is no `throw` keyword, errors are just returned.
|
||||
|
||||
|
||||
### Multiple error returns
|
||||
|
||||
TODO: fix?
|
||||
TODO: properly define syntax, how this interacts with type unions.
|
||||
|
||||
|
||||
|
||||
If there are multiple error types that the function can return,
|
||||
you can use the `|` operator:
|
||||
Multiple errors are chained with `!`. The last one is always
|
||||
the success value.
|
||||
|
||||
<Code thpcode={`
|
||||
type Exceptions = Exception1 | Exception2 | Exception3
|
||||
|
||||
fun sample() -> Int!Exceptions
|
||||
fun sample() -> Error1!Error2!Error3!Int
|
||||
{ /* ... */}
|
||||
`} />
|
||||
|
||||
@ -68,13 +65,13 @@ Use a naked `try` when you want to rethrow an error, if there is any.
|
||||
|
||||
<InteractiveCode
|
||||
code={`
|
||||
fun dangerous() -> Int!Exception
|
||||
fun dangerous() -> Exception!Int
|
||||
{ // May throw randomly
|
||||
return if Math.random() < 0.5 { 50 }
|
||||
else { Exception("Unlucky") }
|
||||
}
|
||||
|
||||
fun run() -> !Exception
|
||||
fun run() -> Exception!
|
||||
{ // If \`dangerous()\` throws, the function exits with the same error.
|
||||
// Otherwise, continues
|
||||
val result = try dangerous()
|
||||
@ -156,7 +153,7 @@ Try/else will assign a new value if an expression fails.
|
||||
|
||||
<InteractiveCode
|
||||
code={`
|
||||
fun run(Int!Exception possible_value)
|
||||
fun run(Exception!Int possible_value)
|
||||
{
|
||||
val mid = try possible_value else 666
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user