Compartilhado, contagem e referência fraca
Quando há mais de um dono legítimo — e o ciclo que a contagem não resolve.
Um dono só nem sempre é possível: um cache, um pool e um barramento de eventos têm vários interessados no mesmo objeto, e nenhum deles sabe quem é o último a sair. A contagem responde isso — e ela é determinística, diferente do coletor.
dataforge
adopt Arcane.Posse as Posse
soltos := []
c := Posse.compartilhado({"conexao": 1}, lambda v => soltos.append("fechou"))
assert c.contar() is 1
// Cada 'clonar' é mais um dono.
b := c.clonar()
d := c.clonar()
assert c.contar() is 3
// E o recurso só fecha quando o ÚLTIMO sai.
c.soltar()
b.soltar()
assert soltos is []
d.soltar()
assert soltos is ["fechou"]"Determinística" é a palavra que importa: o fechamento acontece na linha do último `soltar`, e não quando o coletor decidir passar. Para um arquivo, isso é a diferença entre um descritor liberado agora e um liberado daqui a um minuto.
A referência fraca não conta#
dataforge
adopt Arcane.Posse as Posse
c := Posse.compartilhado({"x": 1})
f := Posse.fraco(c)
// A fraca NÃO segura o recurso vivo.
assert c.contar() is 1
assert f.vivo() is yes
// 'promover' devolve um dono de verdade — ou void, se já foi.
forte := f.promover()
assert forte is not void
assert c.contar() is 2
forte.soltar()
c.soltar()
assert f.vivo() is no
assert f.promover() is voidPara que serve a fraca#
| Caso | Por que fraca |
|---|---|
| um cache de objetos | o cache não pode ser a razão de nada continuar vivo |
| o filho que aponta para o pai | forte nos dois sentidos é um ciclo, e o ciclo nunca zera |
| um observador | quem observa não deveria impedir o observado de sumir |
| um índice por id | ele é uma conveniência, não um dono |
O ciclo, que é o que a contagem não resolve#
dataforge
adopt Arcane.Posse as Posse
// Pai e filho apontando um para o outro com FORTE: a contagem de
// nenhum dos dois chega a zero, e o recurso nunca fecha.
pai := Posse.compartilhado({"nome": "pai"})
filho := Posse.compartilhado({"nome": "filho"})
// A saída: um dos lados é fraco. Aqui, o filho→pai.
fraca_para_o_pai := Posse.fraco(pai)
assert pai.contar() is 1 // a fraca não somou
pai.soltar()
assert fraca_para_o_pai.vivo() is no // e o pai pôde sair
filho.soltar()
out "sem ciclo: o lado de volta é fraco"