Slide 32 de 74

Mutabilidade e semântica de valor

Um segundo nome é uma cópia
proc main(): void {
	mut Str[dyn] a = ["x", "y"]
	b := a                    // uma cópia, até onde se pode perceber
	append(a, "z")
	echo b                    // ["x", "y"]
}
Dois nomes mut compartilham, até um ser reatribuído
proc main(): void {
	mut Str[dyn] a = ["x", "y"]
	mut Str[dyn] b = a        // um armazenamento, dois nomes
	append(b, "z")
	echo a                    // ["x", "y", "z"]

	b = ["replaced"]          // reatribui só b
	echo a                    // ainda os três
}
Um parâmetro mut escreve pela variável de quem chamou
proc grow(vec: mut Str[dyn], tag: Str): void {
	append(vec, tag)
}

proc main(): void {
	mut Str[dyn] tags = ["bee"]
	grow(tags, "hive")
	echo tags                 // ["bee", "hive"]
}

Todo valor em Hive se comporta como valor. Vincular um vetor, uma tabela, um mapa ou um registro a um segundo nome nunca deixa uma escrita por um aparecer no outro — o compilador copia onde precisa, em profundidade, e só pula a cópia onde consegue provar que ninguém perceberia. A exceção é pedida: quando os dois nomes são mut, mut b = a compartilha o armazenamento, então escrever por qualquer um alcança os dois, inclusive append. Reatribuir um deles, b = […], dá àquele nome um armazenamento próprio e deixa o outro com o que eles compartilhavam. Um escalar — um número, uma Str, ou um registro só de escalares — não tem armazenamento para compartilhar, então dois nomes mut para um deles são simplesmente dois valores.

Um parâmetro é uma cópia que o chamado não pode mudar, a menos que seja declarado nome: mut T. Esse é o único lugar em que o armazenamento atravessa uma chamada de propósito: o chamado escreve pela própria variável de quem chamou, então o argumento precisa ser uma variável mut ou um caminho para dentro de uma, como grow(tags) ou grow(box.items). Só um proc pode declarar um, que é o próximo slide.

Uma chamada iniciada numa thread própria com async recebe, em vez disso, uma cópia de cada argumento, feita antes de a thread começar, então os dois lados nunca escrevem no mesmo armazenamento.