Slide 15 de 74

assert e panic

Em código comum, um assert que falha para o programa
func total(prices: Int[]): Int {
	mut sum := 0
	for each p in prices {
		sum += p
	}
	return sum
}

proc main(): void {
	assert total([3, 4]) == 7    // vale: nada acontece
	echo "o carrinho fecha a conta"
	assert total([3, 4]) == 8    // não vale: o programa para, aqui
	echo "nunca alcançado"
}
O que ele imprime
$ hive run basket.hive
o carrinho fecha a conta
panic: hive: assertion failed: total([3, 4]) == 8
	  left:  7
	  right: 8

goroutine 1 [running]:
…
panic fecha um final que o verificador não vê que é inalcançável
func sign(n: Int): Int {
	if n > 0 {
		return 1
	} else if n < 0 {
		return -1
	} else if n == 0 {
		return 0
	}
	// Todo Int é um dos três, mas nada prova isso ao compilador.
	panic "um Int que não é positivo, negativo nem zero: {n}"
}

proc main(): void {
	echo sign(-8)
}

assert cond diz: isto precisa valer. O que acontece quando não vale é decidido por onde está escrito. Em código comum, uma asserção que falha provou que o programa está errado, então o programa para, imprimindo a condição como foi escrita e, para == ou !=, no que cada lado deu. Dentro de um test, ela provou que o teste está errado, então a falha é registrada e o resto da suíte continua rodando — o slide de testes mostra esse relatório. De qualquer forma, seus operandos são avaliados exatamente uma vez, valendo ou não.

panic value para o programa na hora, imprimindo value do jeito que o echo faria — então um átomo imprime seu nome — e aceita qualquer valor, não só um Bool. Ele nunca retorna, então um caminho que termina em panic conta como encerrado, que é o que fecha um final que o verificador não consegue ver que é inalcançável. Um assert não: um que vale segue adiante. Um panic dentro de um teste reprova só aquele teste, e um dentro de um serviço mata só aquele serviço.