Pular para o conteúdo

Funções

Uma função é um pedaço de código com nome, que recebe valores e devolve um resultado. Serve para não repetir o mesmo código em vários sítios: se a conta estiver numa função, corriges num lugar só.

fn <nome>(<parâmetros>) <tipo_retorno> {
// corpo
}

Uma função que não retorna valor omite o tipo de retorno:

fn <nome>(<parâmetros>) {
// corpo
}

Repara que o tipo de retorno vem depois da lista de parâmetros, como em Go, e não antes do nome como em C.

fn soma(int a, int b) int {
divolvi a + b;
}
fn saudacao(textu nome) {
mostran(f"Olá, {nome}!");
}
fn inisiu() {
int resultado = soma(3, 4);
mostran(resultado);
}

inisiu é a única função com regras próprias: não pode ter parâmetros nem declarar um tipo de retorno.

soma(10, 20);
saudacao("Mundo");
int r = soma(1, 2);

Os argumentos são ligados aos parâmetros pela posição, não pelo nome: em soma(10, 20), o 10 vai para a e o 20 para b. Não há argumentos com nome nem valores por omissão, por isso tens de passar sempre todos os parâmetros, e com os tipos certos.

Retorna um valor da função. O tipo deve corresponder ao tipo declarado:

fn dobro(int n) int {
divolvi n * 2;
}

O divolvi termina a função ali mesmo: o código escrito depois dele nunca corre.

Numa função sem tipo de retorno, divolvi pode aparecer sem valor para saída antecipada:

fn imprimeSeNaoNegativo(int n) {
si n < 0 {
divolvi;
}
mostran(f"{n} não é negativo");
}

Na prática, um si sem sinon não chega: precisas de um divolvi final fora do si, mesmo que saibas que a condição cobre todos os casos.

Cada parâmetro recebe uma cópia do valor passado. Alterá-lo dentro da função não muda a variável de quem chamou:

fn tenta_mudar(int n) {
n = 99;
}
fn inisiu() {
int x = 1;
tenta_mudar(x);
mostran(x); // 1, não 99
}

Vale para tudo, incluindo arrays e moldes, que também são valores. Para alterar algo de quem chamou, devolve o novo valor e atribui-o: x = muda(x);. Referências explícitas (ref) estão planeadas para o futuro.

Um parâmetro ou o tipo de retorno pode ser um array de tamanho fixo. O array é copiado, por isso alterá-lo dentro da função não muda o de quem chamou:

fn soma(int[3] v) int {
divolvi v[0] + v[1] + v[2];
}
fn identidade() int[2][2] {
divolvi [[1, 0], [0, 1]];
}

O tamanho faz parte do tipo: uma função que recebe int[3] não aceita um int[4]. Vê Arrays como valores.

Um molde declarado com molda também se usa como tipo de parâmetro e de retorno, e também é copiado; vê Moldes (molda).

O Kriol suporta recursão e recursão mútua. As funções podem ser chamadas antes da sua declaração no ficheiro:

fn par(int n) bool {
si n == 0 { divolvi sin; }
divolvi impar(n - 1);
}
fn impar(int n) bool {
si n == 0 { divolvi nau; }
divolvi par(n - 1);
}
fn inisiu() {
mostran(par(4)); // sin
mostran(impar(3)); // sin
}

Uma função recursiva precisa sempre de um caso que não chama a si mesma, como o n == 0 destes exemplos. Sem ele, a recursão não para e o programa esgota a pilha de 8 MiB que os programas Kriol recebem.

Uma função declara que pode falhar escrevendo : Erru depois do tipo de retorno, e quem a chama trata a falha com tenta ou sinon; vê Erros.

FunçãoDescrição
mostra(...)Imprime os argumentos, sem nova linha no fim
mostran(...)Imprime os argumentos, seguidos de nova linha
toma()Lê uma linha de stdin e retorna textu; pode falhar com Erru (termina o programa se não for tratado; vê tenta e sinon)
konfirma(e), konfirma(e, m)Verifica que e é verdadeiro; termina se falso, com a mensagem m se existir
paniku(m)Termina o programa de imediato com a mensagem m
sai(), sai(código)Termina o programa com o código de saída dado, ou 0 sem argumento

Ao contrário das funções que escreves, mostra e mostran recebem quantos argumentos quiseres, de tipos diferentes, e escrevem-nos seguidos sem nada entre eles:

textu nomi = "Ana";
int idadi = 30;
mostran("Nome: ", nomi, ", idade: ", idadi);
// Nome: Ana, idade: 30

Sem argumento nenhum, mostran() escreve apenas uma linha vazia, prático para separar blocos de saída:

mostran("primeiro bloco");
mostran();
mostran("segundo bloco");

Isto e uma f-string com os mesmos valores dão o mesmo resultado; escolhe a forma que se lê melhor em cada caso.

Um valor de molde não se pode escrever de uma vez em nenhuma das formas; escreve os campos um a um. Vê Strings e Interpolação.

  • Não é permitida a duplicação de funções com o mesmo nome, nem com parâmetros diferentes: não há sobrecarga (overloading).
  • Não há parâmetros com valor por omissão nem argumentos passados por nome.
  • Os parâmetros são passados por valor.
  • A ordem de declaração no ficheiro não afeta a capacidade de chamada entre funções do mesmo ficheiro.
  • Uma função não pode ser declarada dentro de outra; todas vivem no topo do ficheiro.
  • Cada parâmetro e cada valor devolvido ocupa no máximo 1 MiB, porque vive na pilha.