Secrets

In Dyon, a secret is a hidden array of values associated with a bool or f64. The type is sec[bool] or sec[f64].

Secrets are used in combination with any/all/max/min loops. This feature helps developers to write short and correct code.

For example, you can use secrets to find the first item in a list that satisfies a condition:

#![allow(unused)]
fn main() {
list := [1, 2, 3]
a := any i { list[i] > 2 }
if a {
    println(why(a)) // prints `[2]` because `list[2] == 3` and `3 > 2`.
}
}

It also works for lists inside lists:

#![allow(unused)]
fn main() {
list := [[1, 2], [3, 4]]
a := any i, j { list[i][j] > 2 }
if a {
    println(why(a)) // prints `[1, 0]` because `list[1][0] == 3` and `3 > 2`.
}
}

max and min loops uses the where keyword to unlock the secret:

#![allow(unused)]
fn main() {
list := [1, 2, 3, 4]
a := max i { list[i] }
println(where(a)) // prints `[3]` because `list[3]` is the greatest number.
}

Secrets are used to solve problems that otherwise would be a bit tricky to code. For example, the "minimax" algorithm which is used to pick the best move when playing a zero-sum game:

#![allow(unused)]
fn main() {
payoff := [[0, 1], [2, -1]]
a := min i {max j { payoff[i][j] }}
println(where(a)) // prints `[0, 1]` because that is the best move.
}

In the beginning secrets might feel a bit "backwards". Instead of reducing a query into a bool, one can extract information from them! Do not worry, because you will get used to it and you will like this feature when programming complex logic.

Use explain_why to add a secret to a bool:

#![allow(unused)]
fn main() {
a := explain_why(true, "hi!")
if a {
    println(why(a)) // prints `["hi!"]`
}
}

Use explain_where to add a secret to a f64:

#![allow(unused)]
fn main() {
a := explain_where(2.5, "giant")
println(where(a)) // prints `["giant"]`
}

A secret propagates from the left argument of a binary operator:

#![allow(unused)]
fn main() {
a := explain_where(2.5, "giant")
is_tall := a > 2.0
if is_tall {
    println(why(is_tall)) // prints `["giant"]`
}
}

When using a min, max, any or all, the indices are automatically added as secrets:

#![allow(unused)]
fn main() {
list := [[1, 2], [3, 4]]
println(why(any i, j { list[i][j] > 2 })) // prints `[1, 0]`
}

A secret must have meaning

The function why will only work if the value is true. This prevents programs that do not make sense, such as:

#![allow(unused)]
fn main() {
list := [1, 2, 3]
println(why(all i { list[i] < 10 }))
}
--- ERROR ---
main (source/test.dyon)
why

This does not make sense, perhaps an array is empty?
3,17:     println(why(all i { list[i] < 10 }))
3,17:                 ^

Likewise, where will only work if the value is not NaN (0/0):

#![allow(unused)]
fn main() {
list := []
println(where(min i { list[i] }))
}
--- ERROR ---
main (source/test.dyon)

This does not make sense, perhaps an array is empty?
3,19:     println(where(min i { list[i] }))
3,19:                   ^

Remember to check for empty arrays!

Overhead

Since Dyon supports 4D vectors, the size of the Variable enum is quite large. This means better performance for 4D vectors but slower performance for bool and f64. Dyon is designed for game development so this is a reasonable trade-off. The overhead from executing extra instructions for secrets is not that large because of good cache locality.