// function to get (but not set) the person's birth year
fn birth_year(self Person) self.0
// function to get or set the person's name
fn name(self Person/&Person) self.1
person := [1999, "Ryan"]
// Get the values
person.name() // Ryan
person.birth_year() // 1999
// Change the name
&person.name() = "James"
// or: name(&person) = "James"
person.name() // James
// This doesn't compile:
// &person.birth_year() = 1998
```
#### enums are already part of the type system
```
type DirectoryEntry File(string)/Dir(string)/Link(DirectoryEntry)
```
#### return and break
Most people agree that `goto` statements are usually a bad idea.
But `return` and `break` have similar issues, although less severe:
**they create weird control flow:**
Maybe you want to see how long a function takes to execute, so
you add a `println` to the end - just to see absolutely no output.
Now you might think the function is stuck in an infinite loop somewhere,
although it just returned before it ever got to your println.
This can be annoying. If we remove `return` statements,
it becomes way easier to tell when code will or won't be executed.
**return is exclusive to functions, break to loops**
With mers, whenever possible, concepts in the language should work on *statements*.
An example of this are type annotations:
```
fn half(num int) -> int { num / 2 }
```
The `-> int` indicates that this function returns an int.
Actually, it indicates that the statement following it returns an int.
This obviously means the function will also return an int,
but since this syntax isn't specifically made for functions,
we can use it anywhere we want:
```
num := -> int { 4 + 5 }
half(-> int { double * 2})
```
**So how do we return values then?**
Simple!
```
// a function is just another statement
fn return_int() 4 + 5
// a block returns whatever its last statement returns,
fn return_string() {
a := "start"
b := "end"
a + " " + b
}
// this returns string/[], because there is no else
if condition() {
"some value"
}
// this returns string/int
if condition() {
"some value"
} else {
12
}
```
Most returns should be relatively intuitive,
although some special ones (like loops)
use matching (see docs/intro)
### it has references
To explain why this is necessary,
let's look at examples from other languages.
Here is some JavaScript:
```js
function doSmth(list) {
list[0] = 0
}
function modify(num) {
num = 0
}
list = [1]
num = 1
doSmth(list)
modify(num)
console.log(list) // [ 0 ]
console.log(num) // 1
```
The same thing in Go:
```go
package main
import "fmt"
func doSmth(list []int) {
list[0] = 0
}
func modify(num int) {
num = 0
}
func main() {
list := []int{1}
num := 1
doSmth(list)
modify(num)
fmt.Println(list) // [0]
fmt.Println(num) // 1
}
```
In both cases, the function was able to modify the list's contents,
but unable to change the number to a different value.
This is not just inconsistent, it's also not always what you wanted to do:
- i passed the list by value, how could the function change the inner value?
- the function is called `modify`, why can't it modify the value?
+ In Go, we could use references to make this work - but that just makes the list example even more annoying, since we don't need a reference to change the inner value.
So, let's look at mers:
```
fn doSmth(list [int ...]) {
&list.get(0).assume1() = 0
}
fn modify(num &int) {
num = 0
}
list := [1 ...]
num := 1
doSmth(list)
modify(&num)
debug(list) // [1 ...]
debug(num) // 0
```
The list is unchanged, but the number was changed by `modify`,
because it was explicitly passed as a reference `&int`.
**Unless you pass a reference, the value you passed will not be changed.**
### compile-time execution via macros
```
// at compile-time, runs primes.mers to find the first few prime numbers
primes := !(mers "primes.mers")
// at compile-time, runs the code to create a string